Merge
This commit is contained in:
commit
cc14920031
@ -47,11 +47,9 @@ ifeq ($(INCLUDE_GRAAL), true)
|
||||
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_MATCH_PROCESSOR, \
|
||||
SETUP := GENERATE_OLDBYTECODE, \
|
||||
SRC := \
|
||||
$(SRC_DIR)/org.graalvm.compiler.common/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.core/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.core.common/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.core.match.processor/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.api.collections/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.asm/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.bytecode/src \
|
||||
@ -68,6 +66,7 @@ ifeq ($(INCLUDE_GRAAL), true)
|
||||
$(SRC_DIR)/org.graalvm.compiler.phases.common/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.virtual/src \
|
||||
$(SRC_DIR)/org.graalvm.util/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \
|
||||
@ -102,6 +101,7 @@ ifeq ($(INCLUDE_GRAAL), true)
|
||||
SRC := \
|
||||
$(SRC_DIR)/org.graalvm.compiler.options/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.options.processor/src \
|
||||
$(SRC_DIR)/org.graalvm.util/src \
|
||||
, \
|
||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor, \
|
||||
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor.jar, \
|
||||
@ -114,9 +114,7 @@ ifeq ($(INCLUDE_GRAAL), true)
|
||||
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_REPLACEMENTS_VERIFIER, \
|
||||
SETUP := GENERATE_OLDBYTECODE, \
|
||||
SRC := \
|
||||
$(SRC_DIR)/org.graalvm.compiler.common/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.replacements.verifier/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.api.collections/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.code/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.core.common/src \
|
||||
@ -125,6 +123,7 @@ ifeq ($(INCLUDE_GRAAL), true)
|
||||
$(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.options/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
|
||||
$(SRC_DIR)/org.graalvm.util/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
|
||||
$(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \
|
||||
|
@ -37,7 +37,6 @@ SRC_DIR := $(HOTSPOT_TOPDIR)/src/$(MODULE)/share/classes
|
||||
|
||||
PROC_SRC_SUBDIRS := \
|
||||
org.graalvm.compiler.code \
|
||||
org.graalvm.compiler.common \
|
||||
org.graalvm.compiler.core \
|
||||
org.graalvm.compiler.core.aarch64 \
|
||||
org.graalvm.compiler.core.amd64 \
|
||||
|
@ -1,53 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
include $(SPEC)
|
||||
include NativeCompilation.gmk
|
||||
|
||||
$(eval $(call IncludeCustomExtension, hotspot, lib/Lib-jdk.aot.gmk))
|
||||
|
||||
##############################################################################
|
||||
# Build libjelfshim only when AOT is enabled.
|
||||
ifeq ($(ENABLE_AOT), true)
|
||||
JELFSHIM_NAME := jelfshim
|
||||
|
||||
$(eval $(call SetupNativeCompilation, BUILD_LIBJELFSHIM, \
|
||||
TOOLCHAIN := TOOLCHAIN_DEFAULT, \
|
||||
OPTIMIZATION := LOW, \
|
||||
LIBRARY := $(JELFSHIM_NAME), \
|
||||
OUTPUT_DIR := $(call FindLibDirForModule, $(MODULE)), \
|
||||
SRC := $(HOTSPOT_TOPDIR)/src/jdk.aot/unix/native/libjelfshim, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) $(ELF_CFLAGS) \
|
||||
-DAOT_VERSION_STRING='"$(VERSION_STRING)"' \
|
||||
-I$(SUPPORT_OUTPUTDIR)/headers/$(MODULE), \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB), \
|
||||
OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/lib$(JELFSHIM_NAME), \
|
||||
LIBS := $(ELF_LIBS) $(LIBS_JDKLIB), \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_LIBJELFSHIM)
|
||||
endif
|
||||
|
||||
##############################################################################
|
@ -35,12 +35,14 @@ include $(SPEC)
|
||||
include MakeBase.gmk
|
||||
include TestFilesCompilation.gmk
|
||||
|
||||
$(eval $(call IncludeCustomExtension, hotspot, test/JtregNative.gmk))
|
||||
|
||||
################################################################################
|
||||
# Targets for building the native tests themselves.
|
||||
################################################################################
|
||||
|
||||
# Add more directories here when needed.
|
||||
BUILD_HOTSPOT_JTREG_NATIVE_SRC := \
|
||||
BUILD_HOTSPOT_JTREG_NATIVE_SRC += \
|
||||
$(HOTSPOT_TOPDIR)/test/native_sanity \
|
||||
$(HOTSPOT_TOPDIR)/test/runtime/jni/8025979 \
|
||||
$(HOTSPOT_TOPDIR)/test/runtime/jni/8033445 \
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -54,9 +54,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
int number_of_arguments,
|
||||
bool check_exceptions);
|
||||
|
||||
virtual void check_and_handle_popframe(Register java_thread);
|
||||
virtual void check_and_handle_earlyret(Register java_thread);
|
||||
|
||||
// base routine for all dispatches
|
||||
void dispatch_base(TosState state, address* table, bool verifyoop = true);
|
||||
|
||||
@ -67,6 +64,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
|
||||
void jump_to_entry(address entry);
|
||||
|
||||
virtual void check_and_handle_popframe(Register java_thread);
|
||||
virtual void check_and_handle_earlyret(Register java_thread);
|
||||
|
||||
// Interpreter-specific registers
|
||||
void save_bcp() {
|
||||
str(rbcp, Address(rfp, frame::interpreter_frame_bcp_offset * wordSize));
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -55,7 +55,7 @@ void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS)
|
||||
}
|
||||
}
|
||||
#endif // ASSERT
|
||||
Handle obj = HotSpotObjectConstantImpl::object(constant);
|
||||
Handle obj(THREAD, HotSpotObjectConstantImpl::object(constant));
|
||||
jobject value = JNIHandles::make_local(obj());
|
||||
MacroAssembler::patch_oop(pc, (address)obj());
|
||||
int oop_index = _oop_recorder->find_index(value);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -77,12 +77,6 @@ class MacroAssembler: public Assembler {
|
||||
bool check_exceptions // whether to check for pending exceptions after return
|
||||
);
|
||||
|
||||
// These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code.
|
||||
// The implementation is only non-empty for the InterpreterMacroAssembler,
|
||||
// as only the interpreter handles PopFrame and ForceEarlyReturn requests.
|
||||
virtual void check_and_handle_popframe(Register java_thread);
|
||||
virtual void check_and_handle_earlyret(Register java_thread);
|
||||
|
||||
void call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions = true);
|
||||
|
||||
// Maximum size of class area in Metaspace when compressed
|
||||
@ -97,6 +91,12 @@ class MacroAssembler: public Assembler {
|
||||
> (1u << log2_intptr(CompressedClassSpaceSize))));
|
||||
}
|
||||
|
||||
// These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code.
|
||||
// The implementation is only non-empty for the InterpreterMacroAssembler,
|
||||
// as only the interpreter handles PopFrame and ForceEarlyReturn requests.
|
||||
virtual void check_and_handle_popframe(Register java_thread);
|
||||
virtual void check_and_handle_earlyret(Register java_thread);
|
||||
|
||||
// Biased locking support
|
||||
// lock_reg and obj_reg must be loaded up with the appropriate values.
|
||||
// swap_reg is killed.
|
||||
|
@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
|
||||
// Generate the self-patching vtable method:
|
||||
//
|
||||
// This method will be called (as any other Klass virtual method) with
|
||||
// the Klass itself as the first argument. Example:
|
||||
//
|
||||
// oop obj;
|
||||
// int size = obj->klass()->oop_size(this);
|
||||
//
|
||||
// for which the virtual method call is Klass::oop_size();
|
||||
//
|
||||
// The dummy method is called with the Klass object as the first
|
||||
// operand, and an object as the second argument.
|
||||
//
|
||||
|
||||
//=====================================================================
|
||||
|
||||
// All of the dummy methods in the vtable are essentially identical,
|
||||
// differing only by an ordinal constant, and they bear no relationship
|
||||
// to the original method which the caller intended. Also, there needs
|
||||
// to be 'vtbl_list_size' instances of the vtable in order to
|
||||
// differentiate between the 'vtable_list_size' original Klass objects.
|
||||
|
||||
#define __ masm->
|
||||
|
||||
extern "C" {
|
||||
void aarch64_prolog(void);
|
||||
}
|
||||
|
||||
void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
|
||||
void** vtable,
|
||||
char** md_top,
|
||||
char* md_end,
|
||||
char** mc_top,
|
||||
char* mc_end) {
|
||||
|
||||
#ifdef BUILTIN_SIM
|
||||
// Write a dummy word to the writable shared metaspace.
|
||||
// MetaspaceShared::initialize_shared_spaces will fill it with the
|
||||
// address of aarch64_prolog().
|
||||
address *prolog_ptr = (address*)*md_top;
|
||||
*(intptr_t *)(*md_top) = (intptr_t)0;
|
||||
(*md_top) += sizeof(intptr_t);
|
||||
#endif
|
||||
|
||||
intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
|
||||
*(intptr_t *)(*md_top) = vtable_bytes;
|
||||
*md_top += sizeof(intptr_t);
|
||||
void** dummy_vtable = (void**)*md_top;
|
||||
*vtable = dummy_vtable;
|
||||
*md_top += vtable_bytes;
|
||||
|
||||
// Get ready to generate dummy methods.
|
||||
|
||||
CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
|
||||
MacroAssembler* masm = new MacroAssembler(&cb);
|
||||
|
||||
Label common_code;
|
||||
for (int i = 0; i < vtbl_list_size; ++i) {
|
||||
for (int j = 0; j < num_virtuals; ++j) {
|
||||
dummy_vtable[num_virtuals * i + j] = (void*)masm->pc();
|
||||
|
||||
// We're called directly from C code.
|
||||
#ifdef BUILTIN_SIM
|
||||
__ c_stub_prolog(8, 0, MacroAssembler::ret_type_integral, prolog_ptr);
|
||||
#endif
|
||||
// Load rscratch1 with a value indicating vtable/offset pair.
|
||||
// -- bits[ 7..0] (8 bits) which virtual method in table?
|
||||
// -- bits[12..8] (5 bits) which virtual method table?
|
||||
__ mov(rscratch1, (i << 8) + j);
|
||||
__ b(common_code);
|
||||
}
|
||||
}
|
||||
|
||||
__ bind(common_code);
|
||||
|
||||
Register tmp0 = r10, tmp1 = r11; // AAPCS64 temporary registers
|
||||
__ enter();
|
||||
__ lsr(tmp0, rscratch1, 8); // isolate vtable identifier.
|
||||
__ mov(tmp1, (address)vtbl_list); // address of list of vtable pointers.
|
||||
__ ldr(tmp1, Address(tmp1, tmp0, Address::lsl(LogBytesPerWord))); // get correct vtable pointer.
|
||||
__ str(tmp1, Address(c_rarg0)); // update vtable pointer in obj.
|
||||
__ add(rscratch1, tmp1, rscratch1, ext::uxtb, LogBytesPerWord); // address of real method pointer.
|
||||
__ ldr(rscratch1, Address(rscratch1)); // get real method pointer.
|
||||
__ blrt(rscratch1, 8, 0, 1); // jump to the real method.
|
||||
__ leave();
|
||||
__ ret(lr);
|
||||
|
||||
*mc_top = (char*)__ pc();
|
||||
}
|
||||
|
||||
#ifdef BUILTIN_SIM
|
||||
void MetaspaceShared::relocate_vtbl_list(char **buffer) {
|
||||
void **sim_entry = (void**)*buffer;
|
||||
*sim_entry = (void*)aarch64_prolog;
|
||||
*buffer += sizeof(intptr_t);
|
||||
}
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -63,7 +63,7 @@ void MethodHandles::verify_klass(MacroAssembler* _masm,
|
||||
Register obj, SystemDictionary::WKID klass_id,
|
||||
const char* error_message) {
|
||||
InstanceKlass** klass_addr = SystemDictionary::well_known_klass_addr(klass_id);
|
||||
KlassHandle klass = SystemDictionary::well_known_klass(klass_id);
|
||||
Klass* klass = SystemDictionary::well_known_klass(klass_id);
|
||||
Register temp = rscratch2;
|
||||
Register temp2 = rscratch1; // used by MacroAssembler::cmpptr
|
||||
Label L_ok, L_bad;
|
||||
|
@ -402,14 +402,6 @@ address TemplateInterpreterGenerator::generate_exception_handler_common(
|
||||
return entry;
|
||||
}
|
||||
|
||||
address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
|
||||
address entry = __ pc();
|
||||
// NULL last_sp until next java call
|
||||
__ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
|
||||
__ dispatch_next(state);
|
||||
return entry;
|
||||
}
|
||||
|
||||
address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
|
||||
address entry = __ pc();
|
||||
|
||||
@ -444,6 +436,10 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
|
||||
__ notify(Assembler::method_reentry);
|
||||
}
|
||||
#endif
|
||||
|
||||
__ check_and_handle_popframe(rthread);
|
||||
__ check_and_handle_earlyret(rthread);
|
||||
|
||||
__ get_dispatch();
|
||||
__ dispatch_next(state, step);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -234,8 +234,15 @@ void AbstractInterpreter::layout_activation(Method* method,
|
||||
#ifdef AARCH64
|
||||
interpreter_frame->interpreter_frame_set_stack_top(stack_top);
|
||||
|
||||
// We have to add extra reserved slots to max_stack. There are 3 users of the extra slots,
|
||||
// none of which are at the same time, so we just need to make sure there is enough room
|
||||
// for the biggest user:
|
||||
// -reserved slot for exception handler
|
||||
// -reserved slots for JSR292. Method::extra_stack_entries() is the size.
|
||||
// -3 reserved slots so get_method_counters() can save some registers before call_VM().
|
||||
int max_stack = method->constMethod()->max_stack() + MAX2(3, Method::extra_stack_entries());
|
||||
intptr_t* extended_sp = (intptr_t*) monbot -
|
||||
(method->max_stack() + 1) * Interpreter::stackElementWords - // +1 is reserved slot for exception handler
|
||||
(max_stack * Interpreter::stackElementWords) -
|
||||
popframe_extra_args;
|
||||
extended_sp = (intptr_t*)round_down((intptr_t)extended_sp, StackAlignmentInBytes);
|
||||
interpreter_frame->interpreter_frame_set_extended_sp(extended_sp);
|
||||
|
@ -2016,75 +2016,42 @@ void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr,
|
||||
|
||||
void InterpreterMacroAssembler::get_method_counters(Register method,
|
||||
Register Rcounters,
|
||||
Label& skip) {
|
||||
Label& skip,
|
||||
bool saveRegs,
|
||||
Register reg1,
|
||||
Register reg2,
|
||||
Register reg3) {
|
||||
const Address method_counters(method, Method::method_counters_offset());
|
||||
Label has_counters;
|
||||
|
||||
ldr(Rcounters, method_counters);
|
||||
cbnz(Rcounters, has_counters);
|
||||
|
||||
if (saveRegs) {
|
||||
// Save and restore in use caller-saved registers since they will be trashed by call_VM
|
||||
assert(reg1 != noreg, "must specify reg1");
|
||||
assert(reg2 != noreg, "must specify reg2");
|
||||
#ifdef AARCH64
|
||||
const Register tmp = Rcounters;
|
||||
const int saved_regs_size = 20*wordSize;
|
||||
|
||||
// Note: call_VM will cut SP according to Rstack_top value before call, and restore SP to
|
||||
// extended_sp value from frame after the call.
|
||||
// So make sure there is enough stack space to save registers and adjust Rstack_top accordingly.
|
||||
{
|
||||
Label enough_stack_space;
|
||||
check_extended_sp(tmp);
|
||||
sub(Rstack_top, Rstack_top, saved_regs_size);
|
||||
cmp(SP, Rstack_top);
|
||||
b(enough_stack_space, ls);
|
||||
|
||||
align_reg(tmp, Rstack_top, StackAlignmentInBytes);
|
||||
mov(SP, tmp);
|
||||
str(tmp, Address(FP, frame::interpreter_frame_extended_sp_offset * wordSize));
|
||||
|
||||
bind(enough_stack_space);
|
||||
check_stack_top();
|
||||
|
||||
int offset = 0;
|
||||
stp(R0, R1, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
stp(R2, R3, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
stp(R4, R5, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
stp(R6, R7, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
stp(R8, R9, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
stp(R10, R11, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
stp(R12, R13, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
stp(R14, R15, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
stp(R16, R17, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
stp(R18, LR, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
assert (offset == saved_regs_size, "should be");
|
||||
}
|
||||
assert(reg3 != noreg, "must specify reg3");
|
||||
stp(reg1, reg2, Address(Rstack_top, -2*wordSize, pre_indexed));
|
||||
stp(reg3, ZR, Address(Rstack_top, -2*wordSize, pre_indexed));
|
||||
#else
|
||||
push(RegisterSet(R0, R3) | RegisterSet(R12) | RegisterSet(R14));
|
||||
#endif // AARCH64
|
||||
assert(reg3 == noreg, "must not specify reg3");
|
||||
push(RegisterSet(reg1) | RegisterSet(reg2));
|
||||
#endif
|
||||
}
|
||||
|
||||
mov(R1, method);
|
||||
call_VM(noreg, CAST_FROM_FN_PTR(address,
|
||||
InterpreterRuntime::build_method_counters), R1);
|
||||
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::build_method_counters), R1);
|
||||
|
||||
if (saveRegs) {
|
||||
#ifdef AARCH64
|
||||
{
|
||||
int offset = 0;
|
||||
ldp(R0, R1, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
ldp(R2, R3, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
ldp(R4, R5, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
ldp(R6, R7, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
ldp(R8, R9, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
ldp(R10, R11, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
ldp(R12, R13, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
ldp(R14, R15, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
ldp(R16, R17, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
ldp(R18, LR, Address(Rstack_top, offset)); offset += 2*wordSize;
|
||||
assert (offset == saved_regs_size, "should be");
|
||||
|
||||
add(Rstack_top, Rstack_top, saved_regs_size);
|
||||
}
|
||||
ldp(reg3, ZR, Address(Rstack_top, 2*wordSize, post_indexed));
|
||||
ldp(reg1, reg2, Address(Rstack_top, 2*wordSize, post_indexed));
|
||||
#else
|
||||
pop(RegisterSet(R0, R3) | RegisterSet(R12) | RegisterSet(R14));
|
||||
#endif // AARCH64
|
||||
pop(RegisterSet(reg1) | RegisterSet(reg2));
|
||||
#endif
|
||||
}
|
||||
|
||||
ldr(Rcounters, method_counters);
|
||||
cbz(Rcounters, skip); // No MethodCounters created, OutOfMemory
|
||||
|
@ -53,9 +53,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
// Template interpreter specific version of call_VM_helper
|
||||
virtual void call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions);
|
||||
|
||||
virtual void check_and_handle_popframe();
|
||||
virtual void check_and_handle_earlyret();
|
||||
|
||||
// base routine for all dispatches
|
||||
typedef enum { DispatchDefault, DispatchNormal } DispatchTableMode;
|
||||
void dispatch_base(TosState state, DispatchTableMode table_mode, bool verifyoop = true);
|
||||
@ -63,6 +60,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
public:
|
||||
InterpreterMacroAssembler(CodeBuffer* code);
|
||||
|
||||
virtual void check_and_handle_popframe();
|
||||
virtual void check_and_handle_earlyret();
|
||||
|
||||
// Interpreter-specific registers
|
||||
#if defined(AARCH64) && defined(ASSERT)
|
||||
|
||||
@ -328,7 +328,13 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
|
||||
void trace_state(const char* msg) PRODUCT_RETURN;
|
||||
|
||||
void get_method_counters(Register method, Register Rcounters, Label& skip);
|
||||
void get_method_counters(Register method,
|
||||
Register Rcounters,
|
||||
Label& skip,
|
||||
bool saveRegs = false,
|
||||
Register reg1 = noreg,
|
||||
Register reg2 = noreg,
|
||||
Register reg3 = noreg);
|
||||
};
|
||||
|
||||
#endif // CPU_ARM_VM_INTERP_MASM_ARM_HPP
|
||||
|
@ -206,6 +206,9 @@ protected:
|
||||
// may customize this version by overriding it for its purposes (e.g., to save/restore
|
||||
// additional registers when doing a VM call).
|
||||
virtual void call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions);
|
||||
public:
|
||||
|
||||
MacroAssembler(CodeBuffer* code) : Assembler(code) {}
|
||||
|
||||
// These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code.
|
||||
// The implementation is only non-empty for the InterpreterMacroAssembler,
|
||||
@ -213,10 +216,6 @@ protected:
|
||||
virtual void check_and_handle_popframe() {}
|
||||
virtual void check_and_handle_earlyret() {}
|
||||
|
||||
public:
|
||||
|
||||
MacroAssembler(CodeBuffer* code) : Assembler(code) {}
|
||||
|
||||
// By default, we do not need relocation information for non
|
||||
// patchable absolute addresses. However, when needed by some
|
||||
// extensions, ignore_non_patchable_relocations can be modified,
|
||||
|
@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "assembler_arm.inline.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
|
||||
// Generate the self-patching vtable method:
|
||||
//
|
||||
// This method will be called (as any other Klass virtual method) with
|
||||
// the Klass itself as the first argument. Example:
|
||||
//
|
||||
// oop obj;
|
||||
// int size = obj->klass()->oop_size(this);
|
||||
//
|
||||
// for which the virtual method call is Klass::oop_size();
|
||||
//
|
||||
// The dummy method is called with the Klass object as the first
|
||||
// operand, and an object as the second argument.
|
||||
//
|
||||
|
||||
//=====================================================================
|
||||
|
||||
// All of the dummy methods in the vtable are essentially identical,
|
||||
// differing only by an ordinal constant, and they bear no relationship
|
||||
// to the original method which the caller intended. Also, there needs
|
||||
// to be 'vtbl_list_size' instances of the vtable in order to
|
||||
// differentiate between the 'vtable_list_size' original Klass objects.
|
||||
|
||||
#define __ masm->
|
||||
|
||||
void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
|
||||
void** vtable,
|
||||
char** md_top,
|
||||
char* md_end,
|
||||
char** mc_top,
|
||||
char* mc_end) {
|
||||
intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
|
||||
*(intptr_t *)(*md_top) = vtable_bytes;
|
||||
*md_top += sizeof(intptr_t);
|
||||
void** dummy_vtable = (void**)*md_top;
|
||||
*vtable = dummy_vtable;
|
||||
*md_top += vtable_bytes;
|
||||
|
||||
CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
|
||||
MacroAssembler* masm = new MacroAssembler(&cb);
|
||||
|
||||
for (int i = 0; i < vtbl_list_size; ++i) {
|
||||
Label common_code;
|
||||
for (int j = 0; j < num_virtuals; ++j) {
|
||||
dummy_vtable[num_virtuals * i + j] = (void*) __ pc();
|
||||
__ mov(Rtemp, j); // Rtemp contains an index of a virtual method in the table
|
||||
__ b(common_code);
|
||||
}
|
||||
|
||||
InlinedAddress vtable_address((address)&vtbl_list[i]);
|
||||
__ bind(common_code);
|
||||
const Register tmp2 = AARCH64_ONLY(Rtemp2) NOT_AARCH64(R4);
|
||||
assert_different_registers(Rtemp, tmp2);
|
||||
#ifndef AARCH64
|
||||
__ push(tmp2);
|
||||
#endif // !AARCH64
|
||||
// Do not use ldr_global since the code must be portable across all ARM architectures
|
||||
__ ldr_literal(tmp2, vtable_address);
|
||||
__ ldr(tmp2, Address(tmp2)); // get correct vtable address
|
||||
__ ldr(Rtemp, Address::indexed_ptr(tmp2, Rtemp)); // get real method pointer
|
||||
__ str(tmp2, Address(R0)); // update vtable. R0 = "this"
|
||||
#ifndef AARCH64
|
||||
__ pop(tmp2);
|
||||
#endif // !AARCH64
|
||||
__ jump(Rtemp);
|
||||
__ bind_literal(vtable_address);
|
||||
}
|
||||
|
||||
__ flush();
|
||||
*mc_top = (char*) __ pc();
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -67,7 +67,7 @@ void MethodHandles::verify_klass(MacroAssembler* _masm,
|
||||
Register obj, Register temp1, Register temp2, SystemDictionary::WKID klass_id,
|
||||
const char* error_message) {
|
||||
InstanceKlass** klass_addr = SystemDictionary::well_known_klass_addr(klass_id);
|
||||
KlassHandle klass = SystemDictionary::well_known_klass(klass_id);
|
||||
Klass* klass = SystemDictionary::well_known_klass(klass_id);
|
||||
Label L_ok, L_bad;
|
||||
BLOCK_COMMENT("verify_klass {");
|
||||
__ verify_oop(obj);
|
||||
|
@ -270,12 +270,6 @@ address TemplateInterpreterGenerator::generate_exception_handler_common(const ch
|
||||
return entry;
|
||||
}
|
||||
|
||||
address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
|
||||
// Not used.
|
||||
STOP("generate_continuation_for");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
|
||||
address entry = __ pc();
|
||||
|
||||
@ -310,6 +304,9 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
|
||||
__ convert_retval_to_tos(state);
|
||||
#endif // !AARCH64
|
||||
|
||||
__ check_and_handle_popframe();
|
||||
__ check_and_handle_earlyret();
|
||||
|
||||
__ dispatch_next(state, step);
|
||||
|
||||
return entry;
|
||||
@ -1401,7 +1398,13 @@ address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) {
|
||||
#ifdef AARCH64
|
||||
// setup RmaxStack
|
||||
__ ldrh(RmaxStack, Address(RconstMethod, ConstMethod::max_stack_offset()));
|
||||
__ add(RmaxStack, RmaxStack, MAX2(1, Method::extra_stack_entries())); // reserve slots for exception handler and JSR292 appendix argument
|
||||
// We have to add extra reserved slots to max_stack. There are 3 users of the extra slots,
|
||||
// none of which are at the same time, so we just need to make sure there is enough room
|
||||
// for the biggest user:
|
||||
// -reserved slot for exception handler
|
||||
// -reserved slots for JSR292. Method::extra_stack_entries() is the size.
|
||||
// -3 reserved slots so get_method_counters() can save some registers before call_VM().
|
||||
__ add(RmaxStack, RmaxStack, MAX2(3, Method::extra_stack_entries()));
|
||||
#endif // AARCH64
|
||||
|
||||
// see if we've got enough room on the stack for locals plus overhead.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -2286,13 +2286,18 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) {
|
||||
}
|
||||
__ bind(no_mdo);
|
||||
// Increment backedge counter in MethodCounters*
|
||||
__ get_method_counters(Rmethod, Rcounters, dispatch);
|
||||
// Note Rbumped_taken_count is a callee saved registers for ARM32, but caller saved for ARM64
|
||||
__ get_method_counters(Rmethod, Rcounters, dispatch, true /*saveRegs*/,
|
||||
Rdisp, R3_bytecode,
|
||||
AARCH64_ONLY(Rbumped_taken_count) NOT_AARCH64(noreg));
|
||||
const Address mask(Rcounters, in_bytes(MethodCounters::backedge_mask_offset()));
|
||||
__ increment_mask_and_jump(Address(Rcounters, be_offset), increment, mask,
|
||||
Rcnt, R4_tmp, eq, &backedge_counter_overflow);
|
||||
} else {
|
||||
// increment counter
|
||||
__ get_method_counters(Rmethod, Rcounters, dispatch);
|
||||
// Increment backedge counter in MethodCounters*
|
||||
__ get_method_counters(Rmethod, Rcounters, dispatch, true /*saveRegs*/,
|
||||
Rdisp, R3_bytecode,
|
||||
AARCH64_ONLY(Rbumped_taken_count) NOT_AARCH64(noreg));
|
||||
__ ldr_u32(Rtemp, Address(Rcounters, be_offset)); // load backedge counter
|
||||
__ add(Rtemp, Rtemp, InvocationCounter::count_increment); // increment counter
|
||||
__ str_32(Rtemp, Address(Rcounters, be_offset)); // store counter
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2017, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -3177,9 +3177,8 @@ void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) {
|
||||
assert_different_registers(val, crc, res);
|
||||
|
||||
__ load_const_optimized(res, StubRoutines::crc_table_addr(), R0);
|
||||
__ nand(crc, crc, crc); // ~crc
|
||||
__ update_byte_crc32(crc, val, res);
|
||||
__ nand(res, crc, crc); // ~crc
|
||||
__ kernel_crc32_singleByteReg(crc, val, res, true);
|
||||
__ mr(res, crc);
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2017, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -63,18 +63,6 @@ void LIRItem::load_nonconstant() {
|
||||
}
|
||||
|
||||
|
||||
inline void load_int_as_long(LIR_List *ll, LIRItem &li, LIR_Opr dst) {
|
||||
LIR_Opr r = li.value()->operand();
|
||||
if (r->is_register()) {
|
||||
LIR_Opr dst_l = FrameMap::as_long_opr(dst->as_register());
|
||||
ll->convert(Bytecodes::_i2l, li.result(), dst_l); // Convert.
|
||||
} else {
|
||||
// Constants or memory get loaded with sign extend on this platform.
|
||||
ll->move(li.result(), dst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// LIRGenerator
|
||||
//--------------------------------------------------------------
|
||||
@ -1419,10 +1407,9 @@ void LIRGenerator::do_update_CRC32(Intrinsic* x) {
|
||||
arg2 = cc->at(1),
|
||||
arg3 = cc->at(2);
|
||||
|
||||
// CCallingConventionRequiresIntsAsLongs
|
||||
crc.load_item_force(arg1); // We skip int->long conversion here, because CRC32 stub doesn't care about high bits.
|
||||
__ leal(LIR_OprFact::address(a), arg2);
|
||||
load_int_as_long(gen()->lir(), len, arg3);
|
||||
len.load_item_force(arg3); // We skip int->long conversion here, , because CRC32 stub expects int.
|
||||
|
||||
__ call_runtime_leaf(StubRoutines::updateBytesCRC32(), LIR_OprFact::illegalOpr, result_reg, cc->args());
|
||||
__ move(result_reg, result);
|
||||
@ -1434,6 +1421,66 @@ void LIRGenerator::do_update_CRC32(Intrinsic* x) {
|
||||
}
|
||||
}
|
||||
|
||||
void LIRGenerator::do_update_CRC32C(Intrinsic* x) {
|
||||
assert(UseCRC32CIntrinsics, "or should not be here");
|
||||
LIR_Opr result = rlock_result(x);
|
||||
|
||||
switch (x->id()) {
|
||||
case vmIntrinsics::_updateBytesCRC32C:
|
||||
case vmIntrinsics::_updateDirectByteBufferCRC32C: {
|
||||
bool is_updateBytes = (x->id() == vmIntrinsics::_updateBytesCRC32C);
|
||||
|
||||
LIRItem crc(x->argument_at(0), this);
|
||||
LIRItem buf(x->argument_at(1), this);
|
||||
LIRItem off(x->argument_at(2), this);
|
||||
LIRItem len(x->argument_at(3), this);
|
||||
buf.load_item();
|
||||
off.load_nonconstant();
|
||||
|
||||
LIR_Opr index = off.result();
|
||||
int offset = is_updateBytes ? arrayOopDesc::base_offset_in_bytes(T_BYTE) : 0;
|
||||
if (off.result()->is_constant()) {
|
||||
index = LIR_OprFact::illegalOpr;
|
||||
offset += off.result()->as_jint();
|
||||
}
|
||||
LIR_Opr base_op = buf.result();
|
||||
LIR_Address* a = NULL;
|
||||
|
||||
if (index->is_valid()) {
|
||||
LIR_Opr tmp = new_register(T_LONG);
|
||||
__ convert(Bytecodes::_i2l, index, tmp);
|
||||
index = tmp;
|
||||
__ add(index, LIR_OprFact::intptrConst(offset), index);
|
||||
a = new LIR_Address(base_op, index, T_BYTE);
|
||||
} else {
|
||||
a = new LIR_Address(base_op, offset, T_BYTE);
|
||||
}
|
||||
|
||||
BasicTypeList signature(3);
|
||||
signature.append(T_INT);
|
||||
signature.append(T_ADDRESS);
|
||||
signature.append(T_INT);
|
||||
CallingConvention* cc = frame_map()->c_calling_convention(&signature);
|
||||
const LIR_Opr result_reg = result_register_for(x->type());
|
||||
|
||||
LIR_Opr arg1 = cc->at(0),
|
||||
arg2 = cc->at(1),
|
||||
arg3 = cc->at(2);
|
||||
|
||||
crc.load_item_force(arg1); // We skip int->long conversion here, because CRC32 stub doesn't care about high bits.
|
||||
__ leal(LIR_OprFact::address(a), arg2);
|
||||
len.load_item_force(arg3); // We skip int->long conversion here, , because CRC32 stub expects int.
|
||||
|
||||
__ call_runtime_leaf(StubRoutines::updateBytesCRC32C(), LIR_OprFact::illegalOpr, result_reg, cc->args());
|
||||
__ move(result_reg, result);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) {
|
||||
assert(x->number_of_arguments() == 3, "wrong type");
|
||||
assert(UseFMA, "Needs FMA instructions support.");
|
||||
@ -1460,7 +1507,3 @@ void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) {
|
||||
void LIRGenerator::do_vectorizedMismatch(Intrinsic* x) {
|
||||
fatal("vectorizedMismatch intrinsic is not implemented on this platform");
|
||||
}
|
||||
|
||||
void LIRGenerator::do_update_CRC32C(Intrinsic* x) {
|
||||
Unimplemented();
|
||||
}
|
||||
|
@ -45,8 +45,8 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
#define thread_(field_name) in_bytes(JavaThread::field_name ## _offset()), R16_thread
|
||||
#define method_(field_name) in_bytes(Method::field_name ## _offset()), R19_method
|
||||
|
||||
virtual void check_and_handle_popframe(Register java_thread);
|
||||
virtual void check_and_handle_earlyret(Register java_thread);
|
||||
virtual void check_and_handle_popframe(Register scratch_reg);
|
||||
virtual void check_and_handle_earlyret(Register scratch_reg);
|
||||
|
||||
// Base routine for all dispatches.
|
||||
void dispatch_base(TosState state, address* table);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2017 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2012, 2017, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -4120,7 +4120,7 @@ void MacroAssembler::update_byte_crc32(Register crc, Register val, Register tabl
|
||||
* @param table register pointing to CRC table
|
||||
*/
|
||||
void MacroAssembler::update_byteLoop_crc32(Register crc, Register buf, Register len, Register table,
|
||||
Register data, bool loopAlignment, bool invertCRC) {
|
||||
Register data, bool loopAlignment) {
|
||||
assert_different_registers(crc, buf, len, table, data);
|
||||
|
||||
Label L_mainLoop, L_done;
|
||||
@ -4131,10 +4131,6 @@ void MacroAssembler::update_byteLoop_crc32(Register crc, Register buf, Register
|
||||
clrldi_(len, len, 32); // Enforce 32 bit. Anything to do?
|
||||
beq(CCR0, L_done);
|
||||
|
||||
if (invertCRC) {
|
||||
nand(crc, crc, crc); // ~c
|
||||
}
|
||||
|
||||
mtctr(len);
|
||||
align(mainLoop_alignment);
|
||||
BIND(L_mainLoop);
|
||||
@ -4143,10 +4139,6 @@ void MacroAssembler::update_byteLoop_crc32(Register crc, Register buf, Register
|
||||
update_byte_crc32(crc, data, table);
|
||||
bdnz(L_mainLoop); // Iterate.
|
||||
|
||||
if (invertCRC) {
|
||||
nand(crc, crc, crc); // ~c
|
||||
}
|
||||
|
||||
bind(L_done);
|
||||
}
|
||||
|
||||
@ -4203,7 +4195,8 @@ void MacroAssembler::update_1word_crc32(Register crc, Register buf, Register tab
|
||||
*/
|
||||
void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len, Register table,
|
||||
Register t0, Register t1, Register t2, Register t3,
|
||||
Register tc0, Register tc1, Register tc2, Register tc3) {
|
||||
Register tc0, Register tc1, Register tc2, Register tc3,
|
||||
bool invertCRC) {
|
||||
assert_different_registers(crc, buf, len, table);
|
||||
|
||||
Label L_mainLoop, L_tail;
|
||||
@ -4217,14 +4210,16 @@ void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len
|
||||
const int complexThreshold = 2*mainLoop_stepping;
|
||||
|
||||
// Don't test for len <= 0 here. This pathological case should not occur anyway.
|
||||
// Optimizing for it by adding a test and a branch seems to be a waste of CPU cycles.
|
||||
// The situation itself is detected and handled correctly by the conditional branches
|
||||
// following aghi(len, -stepping) and aghi(len, +stepping).
|
||||
// Optimizing for it by adding a test and a branch seems to be a waste of CPU cycles
|
||||
// for all well-behaved cases. The situation itself is detected and handled correctly
|
||||
// within update_byteLoop_crc32.
|
||||
assert(tailLoop_stepping == 1, "check tailLoop_stepping!");
|
||||
|
||||
BLOCK_COMMENT("kernel_crc32_2word {");
|
||||
|
||||
nand(crc, crc, crc); // ~c
|
||||
if (invertCRC) {
|
||||
nand(crc, crc, crc); // 1s complement of crc
|
||||
}
|
||||
|
||||
// Check for short (<mainLoop_stepping) buffer.
|
||||
cmpdi(CCR0, len, complexThreshold);
|
||||
@ -4245,7 +4240,7 @@ void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len
|
||||
blt(CCR0, L_tail); // For less than one mainloop_stepping left, do only tail processing
|
||||
mr(len, tmp); // remaining bytes for main loop (>=mainLoop_stepping is guaranteed).
|
||||
}
|
||||
update_byteLoop_crc32(crc, buf, tmp2, table, data, false, false);
|
||||
update_byteLoop_crc32(crc, buf, tmp2, table, data, false);
|
||||
}
|
||||
|
||||
srdi(tmp2, len, log_stepping); // #iterations for mainLoop
|
||||
@ -4281,9 +4276,11 @@ void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len
|
||||
|
||||
// Process last few (<complexThreshold) bytes of buffer.
|
||||
BIND(L_tail);
|
||||
update_byteLoop_crc32(crc, buf, len, table, data, false, false);
|
||||
update_byteLoop_crc32(crc, buf, len, table, data, false);
|
||||
|
||||
nand(crc, crc, crc); // ~c
|
||||
if (invertCRC) {
|
||||
nand(crc, crc, crc); // 1s complement of crc
|
||||
}
|
||||
BLOCK_COMMENT("} kernel_crc32_2word");
|
||||
}
|
||||
|
||||
@ -4297,7 +4294,8 @@ void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len
|
||||
*/
|
||||
void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len, Register table,
|
||||
Register t0, Register t1, Register t2, Register t3,
|
||||
Register tc0, Register tc1, Register tc2, Register tc3) {
|
||||
Register tc0, Register tc1, Register tc2, Register tc3,
|
||||
bool invertCRC) {
|
||||
assert_different_registers(crc, buf, len, table);
|
||||
|
||||
Label L_mainLoop, L_tail;
|
||||
@ -4311,14 +4309,16 @@ void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len
|
||||
const int complexThreshold = 2*mainLoop_stepping;
|
||||
|
||||
// Don't test for len <= 0 here. This pathological case should not occur anyway.
|
||||
// Optimizing for it by adding a test and a branch seems to be a waste of CPU cycles.
|
||||
// The situation itself is detected and handled correctly by the conditional branches
|
||||
// following aghi(len, -stepping) and aghi(len, +stepping).
|
||||
// Optimizing for it by adding a test and a branch seems to be a waste of CPU cycles
|
||||
// for all well-behaved cases. The situation itself is detected and handled correctly
|
||||
// within update_byteLoop_crc32.
|
||||
assert(tailLoop_stepping == 1, "check tailLoop_stepping!");
|
||||
|
||||
BLOCK_COMMENT("kernel_crc32_1word {");
|
||||
|
||||
nand(crc, crc, crc); // ~c
|
||||
if (invertCRC) {
|
||||
nand(crc, crc, crc); // 1s complement of crc
|
||||
}
|
||||
|
||||
// Check for short (<mainLoop_stepping) buffer.
|
||||
cmpdi(CCR0, len, complexThreshold);
|
||||
@ -4339,7 +4339,7 @@ void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len
|
||||
blt(CCR0, L_tail); // For less than one mainloop_stepping left, do only tail processing
|
||||
mr(len, tmp); // remaining bytes for main loop (>=mainLoop_stepping is guaranteed).
|
||||
}
|
||||
update_byteLoop_crc32(crc, buf, tmp2, table, data, false, false);
|
||||
update_byteLoop_crc32(crc, buf, tmp2, table, data, false);
|
||||
}
|
||||
|
||||
srdi(tmp2, len, log_stepping); // #iterations for mainLoop
|
||||
@ -4374,9 +4374,11 @@ void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len
|
||||
|
||||
// Process last few (<complexThreshold) bytes of buffer.
|
||||
BIND(L_tail);
|
||||
update_byteLoop_crc32(crc, buf, len, table, data, false, false);
|
||||
update_byteLoop_crc32(crc, buf, len, table, data, false);
|
||||
|
||||
nand(crc, crc, crc); // ~c
|
||||
if (invertCRC) {
|
||||
nand(crc, crc, crc); // 1s complement of crc
|
||||
}
|
||||
BLOCK_COMMENT("} kernel_crc32_1word");
|
||||
}
|
||||
|
||||
@ -4389,16 +4391,24 @@ void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len
|
||||
* Uses R7_ARG5, R8_ARG6 as work registers.
|
||||
*/
|
||||
void MacroAssembler::kernel_crc32_1byte(Register crc, Register buf, Register len, Register table,
|
||||
Register t0, Register t1, Register t2, Register t3) {
|
||||
Register t0, Register t1, Register t2, Register t3,
|
||||
bool invertCRC) {
|
||||
assert_different_registers(crc, buf, len, table);
|
||||
|
||||
Register data = t0; // Holds the current byte to be folded into crc.
|
||||
|
||||
BLOCK_COMMENT("kernel_crc32_1byte {");
|
||||
|
||||
// Process all bytes in a single-byte loop.
|
||||
update_byteLoop_crc32(crc, buf, len, table, data, true, true);
|
||||
if (invertCRC) {
|
||||
nand(crc, crc, crc); // 1s complement of crc
|
||||
}
|
||||
|
||||
// Process all bytes in a single-byte loop.
|
||||
update_byteLoop_crc32(crc, buf, len, table, data, true);
|
||||
|
||||
if (invertCRC) {
|
||||
nand(crc, crc, crc); // 1s complement of crc
|
||||
}
|
||||
BLOCK_COMMENT("} kernel_crc32_1byte");
|
||||
}
|
||||
|
||||
@ -4416,7 +4426,8 @@ void MacroAssembler::kernel_crc32_1byte(Register crc, Register buf, Register len
|
||||
*/
|
||||
void MacroAssembler::kernel_crc32_1word_vpmsumd(Register crc, Register buf, Register len, Register table,
|
||||
Register constants, Register barretConstants,
|
||||
Register t0, Register t1, Register t2, Register t3, Register t4) {
|
||||
Register t0, Register t1, Register t2, Register t3, Register t4,
|
||||
bool invertCRC) {
|
||||
assert_different_registers(crc, buf, len, table);
|
||||
|
||||
Label L_alignedHead, L_tail, L_alignTail, L_start, L_end;
|
||||
@ -4434,13 +4445,15 @@ void MacroAssembler::kernel_crc32_1word_vpmsumd(Register crc, Register buf, Regi
|
||||
Register tc0 = t4;
|
||||
Register tc1 = constants;
|
||||
Register tc2 = barretConstants;
|
||||
kernel_crc32_1word(crc, buf, len, table,t0, t1, t2, t3, tc0, tc1, tc2, table);
|
||||
kernel_crc32_1word(crc, buf, len, table,t0, t1, t2, t3, tc0, tc1, tc2, table, invertCRC);
|
||||
b(L_end);
|
||||
|
||||
BIND(L_start);
|
||||
|
||||
// 2. ~c
|
||||
nand(crc, crc, crc);
|
||||
if (invertCRC) {
|
||||
nand(crc, crc, crc); // 1s complement of crc
|
||||
}
|
||||
|
||||
// 3. calculate from 0 to first 128bit-aligned address
|
||||
clrldi_(prealign, buf, 57);
|
||||
@ -4449,7 +4462,7 @@ void MacroAssembler::kernel_crc32_1word_vpmsumd(Register crc, Register buf, Regi
|
||||
subfic(prealign, prealign, 128);
|
||||
|
||||
subf(len, prealign, len);
|
||||
update_byteLoop_crc32(crc, buf, prealign, table, t2, false, false);
|
||||
update_byteLoop_crc32(crc, buf, prealign, table, t2, false);
|
||||
|
||||
// 4. calculate from first 128bit-aligned address to last 128bit-aligned address
|
||||
BIND(L_alignedHead);
|
||||
@ -4464,12 +4477,14 @@ void MacroAssembler::kernel_crc32_1word_vpmsumd(Register crc, Register buf, Regi
|
||||
cmpdi(CCR0, postalign, 0);
|
||||
beq(CCR0, L_tail);
|
||||
|
||||
update_byteLoop_crc32(crc, buf, postalign, table, t2, false, false);
|
||||
update_byteLoop_crc32(crc, buf, postalign, table, t2, false);
|
||||
|
||||
BIND(L_tail);
|
||||
|
||||
// 6. ~c
|
||||
nand(crc, crc, crc);
|
||||
if (invertCRC) {
|
||||
nand(crc, crc, crc); // 1s complement of crc
|
||||
}
|
||||
|
||||
BIND(L_end);
|
||||
|
||||
@ -4961,16 +4976,35 @@ void MacroAssembler::kernel_crc32_1word_aligned(Register crc, Register buf, Regi
|
||||
offsetInt -= 8; ld(R31, offsetInt, R1_SP);
|
||||
}
|
||||
|
||||
void MacroAssembler::kernel_crc32_singleByte(Register crc, Register buf, Register len, Register table, Register tmp) {
|
||||
void MacroAssembler::kernel_crc32_singleByte(Register crc, Register buf, Register len, Register table, Register tmp, bool invertCRC) {
|
||||
assert_different_registers(crc, buf, /* len, not used!! */ table, tmp);
|
||||
|
||||
BLOCK_COMMENT("kernel_crc32_singleByte:");
|
||||
nand(crc, crc, crc); // ~c
|
||||
if (invertCRC) {
|
||||
nand(crc, crc, crc); // 1s complement of crc
|
||||
}
|
||||
|
||||
lbz(tmp, 0, buf); // Byte from buffer, zero-extended.
|
||||
lbz(tmp, 0, buf); // Byte from buffer, zero-extended.
|
||||
update_byte_crc32(crc, tmp, table);
|
||||
|
||||
nand(crc, crc, crc); // ~c
|
||||
if (invertCRC) {
|
||||
nand(crc, crc, crc); // 1s complement of crc
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::kernel_crc32_singleByteReg(Register crc, Register val, Register table, bool invertCRC) {
|
||||
assert_different_registers(crc, val, table);
|
||||
|
||||
BLOCK_COMMENT("kernel_crc32_singleByteReg:");
|
||||
if (invertCRC) {
|
||||
nand(crc, crc, crc); // 1s complement of crc
|
||||
}
|
||||
|
||||
update_byte_crc32(crc, val, table);
|
||||
|
||||
if (invertCRC) {
|
||||
nand(crc, crc, crc); // 1s complement of crc
|
||||
}
|
||||
}
|
||||
|
||||
// dest_lo += src1 + src2
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2017 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2012, 2017, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -819,33 +819,47 @@ class MacroAssembler: public Assembler {
|
||||
Register tmp6, Register tmp7, Register tmp8, Register tmp9, Register tmp10,
|
||||
Register tmp11, Register tmp12, Register tmp13);
|
||||
|
||||
// CRC32 Intrinsics.
|
||||
// Emitters for CRC32 calculation.
|
||||
// A note on invertCRC:
|
||||
// Unfortunately, internal representation of crc differs between CRC32 and CRC32C.
|
||||
// CRC32 holds it's current crc value in the externally visible representation.
|
||||
// CRC32C holds it's current crc value in internal format, ready for updating.
|
||||
// Thus, the crc value must be bit-flipped before updating it in the CRC32 case.
|
||||
// In the CRC32C case, it must be bit-flipped when it is given to the outside world (getValue()).
|
||||
// The bool invertCRC parameter indicates whether bit-flipping is required before updates.
|
||||
void load_reverse_32(Register dst, Register src);
|
||||
int crc32_table_columns(Register table, Register tc0, Register tc1, Register tc2, Register tc3);
|
||||
void fold_byte_crc32(Register crc, Register val, Register table, Register tmp);
|
||||
void fold_8bit_crc32(Register crc, Register table, Register tmp);
|
||||
void update_byte_crc32(Register crc, Register val, Register table);
|
||||
void update_byteLoop_crc32(Register crc, Register buf, Register len, Register table,
|
||||
Register data, bool loopAlignment, bool invertCRC);
|
||||
Register data, bool loopAlignment);
|
||||
void update_1word_crc32(Register crc, Register buf, Register table, int bufDisp, int bufInc,
|
||||
Register t0, Register t1, Register t2, Register t3,
|
||||
Register tc0, Register tc1, Register tc2, Register tc3);
|
||||
void kernel_crc32_2word(Register crc, Register buf, Register len, Register table,
|
||||
Register t0, Register t1, Register t2, Register t3,
|
||||
Register tc0, Register tc1, Register tc2, Register tc3);
|
||||
Register tc0, Register tc1, Register tc2, Register tc3,
|
||||
bool invertCRC);
|
||||
void kernel_crc32_1word(Register crc, Register buf, Register len, Register table,
|
||||
Register t0, Register t1, Register t2, Register t3,
|
||||
Register tc0, Register tc1, Register tc2, Register tc3);
|
||||
Register tc0, Register tc1, Register tc2, Register tc3,
|
||||
bool invertCRC);
|
||||
void kernel_crc32_1byte(Register crc, Register buf, Register len, Register table,
|
||||
Register t0, Register t1, Register t2, Register t3);
|
||||
Register t0, Register t1, Register t2, Register t3,
|
||||
bool invertCRC);
|
||||
void kernel_crc32_1word_vpmsumd(Register crc, Register buf, Register len, Register table,
|
||||
Register constants, Register barretConstants,
|
||||
Register t0, Register t1, Register t2, Register t3, Register t4);
|
||||
Register t0, Register t1, Register t2, Register t3, Register t4,
|
||||
bool invertCRC);
|
||||
void kernel_crc32_1word_aligned(Register crc, Register buf, Register len,
|
||||
Register constants, Register barretConstants,
|
||||
Register t0, Register t1, Register t2);
|
||||
|
||||
void kernel_crc32_singleByte(Register crc, Register buf, Register len, Register table, Register tmp);
|
||||
void kernel_crc32_singleByte(Register crc, Register buf, Register len, Register table, Register tmp,
|
||||
bool invertCRC);
|
||||
void kernel_crc32_singleByteReg(Register crc, Register val, Register table,
|
||||
bool invertCRC);
|
||||
|
||||
//
|
||||
// Debugging
|
||||
|
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2013 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "asm/codeBuffer.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
|
||||
// Generate the self-patching vtable method:
|
||||
//
|
||||
// This method will be called (as any other Klass virtual method) with
|
||||
// the Klass itself as the first argument. Example:
|
||||
//
|
||||
// oop obj;
|
||||
// int size = obj->klass()->klass_part()->oop_size(this);
|
||||
//
|
||||
// for which the virtual method call is Klass::oop_size();
|
||||
//
|
||||
// The dummy method is called with the Klass object as the first
|
||||
// operand, and an object as the second argument.
|
||||
//
|
||||
|
||||
//=====================================================================
|
||||
|
||||
// All of the dummy methods in the vtable are essentially identical,
|
||||
// differing only by an ordinal constant, and they bear no releationship
|
||||
// to the original method which the caller intended. Also, there needs
|
||||
// to be 'vtbl_list_size' instances of the vtable in order to
|
||||
// differentiate between the 'vtable_list_size' original Klass objects.
|
||||
|
||||
#define __ masm->
|
||||
|
||||
void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
|
||||
void** vtable,
|
||||
char** md_top,
|
||||
char* md_end,
|
||||
char** mc_top,
|
||||
char* mc_end) {
|
||||
intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
|
||||
*(intptr_t *)(*md_top) = vtable_bytes;
|
||||
*md_top += sizeof(intptr_t);
|
||||
void** dummy_vtable = (void**)*md_top;
|
||||
*vtable = dummy_vtable;
|
||||
*md_top += vtable_bytes;
|
||||
|
||||
// Get ready to generate dummy methods.
|
||||
|
||||
CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
|
||||
MacroAssembler* masm = new MacroAssembler(&cb);
|
||||
|
||||
// There are more general problems with CDS on ppc, so I can not
|
||||
// really test this. But having this instead of Unimplementd() allows
|
||||
// us to pass TestOptionsWithRanges.java.
|
||||
__ unimplemented();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -71,7 +71,7 @@ void MethodHandles::verify_klass(MacroAssembler* _masm,
|
||||
Register temp_reg, Register temp2_reg,
|
||||
const char* error_message) {
|
||||
InstanceKlass** klass_addr = SystemDictionary::well_known_klass_addr(klass_id);
|
||||
KlassHandle klass = SystemDictionary::well_known_klass(klass_id);
|
||||
Klass* klass = SystemDictionary::well_known_klass(klass_id);
|
||||
Label L_ok, L_bad;
|
||||
BLOCK_COMMENT("verify_klass {");
|
||||
__ verify_oop(obj_reg);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2017, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -3276,6 +3276,36 @@ class StubGenerator: public StubCodeGenerator {
|
||||
return start;
|
||||
}
|
||||
|
||||
|
||||
// Compute CRC32/CRC32C function.
|
||||
void generate_CRC_updateBytes(const char* name, Register table, bool invertCRC) {
|
||||
|
||||
// arguments to kernel_crc32:
|
||||
const Register crc = R3_ARG1; // Current checksum, preset by caller or result from previous call.
|
||||
const Register data = R4_ARG2; // source byte array
|
||||
const Register dataLen = R5_ARG3; // #bytes to process
|
||||
|
||||
const Register t0 = R2;
|
||||
const Register t1 = R7;
|
||||
const Register t2 = R8;
|
||||
const Register t3 = R9;
|
||||
const Register tc0 = R10;
|
||||
const Register tc1 = R11;
|
||||
const Register tc2 = R12;
|
||||
|
||||
BLOCK_COMMENT("Stub body {");
|
||||
assert_different_registers(crc, data, dataLen, table);
|
||||
|
||||
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, tc0, tc1, tc2, table, invertCRC);
|
||||
|
||||
BLOCK_COMMENT("return");
|
||||
__ mr_if_needed(R3_RET, crc); // Updated crc is function result. No copying required (R3_ARG1 == R3_RET).
|
||||
__ blr();
|
||||
|
||||
BLOCK_COMMENT("} Stub body");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Arguments:
|
||||
*
|
||||
@ -3296,14 +3326,14 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
address start = __ function_entry(); // Remember stub start address (is rtn value).
|
||||
|
||||
const Register table = R6; // crc table address
|
||||
|
||||
#ifdef VM_LITTLE_ENDIAN
|
||||
// arguments to kernel_crc32:
|
||||
const Register crc = R3_ARG1; // Current checksum, preset by caller or result from previous call.
|
||||
const Register data = R4_ARG2; // source byte array
|
||||
const Register dataLen = R5_ARG3; // #bytes to process
|
||||
|
||||
const Register table = R6; // crc table address
|
||||
|
||||
#ifdef VM_LITTLE_ENDIAN
|
||||
if (VM_Version::has_vpmsumb()) {
|
||||
const Register constants = R2; // constants address
|
||||
const Register bconstants = R8; // barret table address
|
||||
@ -3321,7 +3351,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubRoutines::ppc64::generate_load_crc_constants_addr(_masm, constants);
|
||||
StubRoutines::ppc64::generate_load_crc_barret_constants_addr(_masm, bconstants);
|
||||
|
||||
__ kernel_crc32_1word_vpmsumd(crc, data, dataLen, table, constants, bconstants, t0, t1, t2, t3, t4);
|
||||
__ kernel_crc32_1word_vpmsumd(crc, data, dataLen, table, constants, bconstants, t0, t1, t2, t3, t4, true);
|
||||
|
||||
BLOCK_COMMENT("return");
|
||||
__ mr_if_needed(R3_RET, crc); // Updated crc is function result. No copying required (R3_ARG1 == R3_RET).
|
||||
@ -3331,31 +3361,79 @@ class StubGenerator: public StubCodeGenerator {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
const Register t0 = R2;
|
||||
const Register t1 = R7;
|
||||
const Register t2 = R8;
|
||||
const Register t3 = R9;
|
||||
const Register tc0 = R10;
|
||||
const Register tc1 = R11;
|
||||
const Register tc2 = R12;
|
||||
StubRoutines::ppc64::generate_load_crc_table_addr(_masm, table);
|
||||
generate_CRC_updateBytes(name, table, true);
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Arguments:
|
||||
*
|
||||
* Inputs:
|
||||
* R3_ARG1 - int crc
|
||||
* R4_ARG2 - byte* buf
|
||||
* R5_ARG3 - int length (of buffer)
|
||||
*
|
||||
* scratch:
|
||||
* R2, R6-R12
|
||||
*
|
||||
* Ouput:
|
||||
* R3_RET - int crc result
|
||||
*/
|
||||
// Compute CRC32C function.
|
||||
address generate_CRC32C_updateBytes(const char* name) {
|
||||
__ align(CodeEntryAlignment);
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
address start = __ function_entry(); // Remember stub start address (is rtn value).
|
||||
|
||||
const Register table = R6; // crc table address
|
||||
|
||||
#if 0 // no vector support yet for CRC32C
|
||||
#ifdef VM_LITTLE_ENDIAN
|
||||
// arguments to kernel_crc32:
|
||||
const Register crc = R3_ARG1; // Current checksum, preset by caller or result from previous call.
|
||||
const Register data = R4_ARG2; // source byte array
|
||||
const Register dataLen = R5_ARG3; // #bytes to process
|
||||
|
||||
if (VM_Version::has_vpmsumb()) {
|
||||
const Register constants = R2; // constants address
|
||||
const Register bconstants = R8; // barret table address
|
||||
|
||||
const Register t0 = R9;
|
||||
const Register t1 = R10;
|
||||
const Register t2 = R11;
|
||||
const Register t3 = R12;
|
||||
const Register t4 = R7;
|
||||
|
||||
BLOCK_COMMENT("Stub body {");
|
||||
assert_different_registers(crc, data, dataLen, table);
|
||||
|
||||
StubRoutines::ppc64::generate_load_crc_table_addr(_masm, table);
|
||||
StubRoutines::ppc64::generate_load_crc32c_table_addr(_masm, table);
|
||||
StubRoutines::ppc64::generate_load_crc32c_constants_addr(_masm, constants);
|
||||
StubRoutines::ppc64::generate_load_crc32c_barret_constants_addr(_masm, bconstants);
|
||||
|
||||
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, tc0, tc1, tc2, table);
|
||||
__ kernel_crc32_1word_vpmsumd(crc, data, dataLen, table, constants, bconstants, t0, t1, t2, t3, t4, false);
|
||||
|
||||
BLOCK_COMMENT("return");
|
||||
__ mr_if_needed(R3_RET, crc); // Updated crc is function result. No copying required (R3_ARG1 == R3_RET).
|
||||
__ blr();
|
||||
|
||||
BLOCK_COMMENT("} Stub body");
|
||||
} else
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
StubRoutines::ppc64::generate_load_crc32c_table_addr(_masm, table);
|
||||
generate_CRC_updateBytes(name, table, false);
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
|
||||
// Initialization
|
||||
void generate_initial() {
|
||||
// Generates all stubs and initializes the entry points
|
||||
@ -3383,6 +3461,12 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubRoutines::_crc_table_adr = (address)StubRoutines::ppc64::_crc_table;
|
||||
StubRoutines::_updateBytesCRC32 = generate_CRC32_updateBytes("CRC32_updateBytes");
|
||||
}
|
||||
|
||||
// CRC32C Intrinsics.
|
||||
if (UseCRC32CIntrinsics) {
|
||||
StubRoutines::_crc32c_table_addr = (address)StubRoutines::ppc64::_crc32c_table;
|
||||
StubRoutines::_updateBytesCRC32C = generate_CRC32C_updateBytes("CRC32C_updateBytes");
|
||||
}
|
||||
}
|
||||
|
||||
void generate_all() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2017, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -55,13 +55,16 @@ class ppc64 {
|
||||
|
||||
// CRC32 Intrinsics.
|
||||
static juint _crc_table[CRC32_TABLES][CRC32_COLUMN_SIZE];
|
||||
static juint _crc32c_table[CRC32_TABLES][CRC32_COLUMN_SIZE];
|
||||
static juint* _constants;
|
||||
static juint* _barret_constants;
|
||||
|
||||
public:
|
||||
|
||||
// CRC32 Intrinsics.
|
||||
static void generate_load_table_addr(MacroAssembler* masm, Register table, address table_addr, uint64_t table_contents);
|
||||
static void generate_load_crc_table_addr(MacroAssembler* masm, Register table);
|
||||
static void generate_load_crc32c_table_addr(MacroAssembler* masm, Register table);
|
||||
static void generate_load_crc_constants_addr(MacroAssembler* masm, Register table);
|
||||
static void generate_load_crc_barret_constants_addr(MacroAssembler* masm, Register table);
|
||||
static juint* generate_crc_constants();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2017 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2015, 2017, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -643,12 +643,6 @@ address TemplateInterpreterGenerator::generate_exception_handler_common(const ch
|
||||
return entry;
|
||||
}
|
||||
|
||||
address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
|
||||
address entry = __ pc();
|
||||
__ unimplemented("generate_continuation_for");
|
||||
return entry;
|
||||
}
|
||||
|
||||
// This entry is returned to when a call returns to the interpreter.
|
||||
// When we arrive here, we expect that the callee stack frame is already popped.
|
||||
address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
|
||||
@ -692,6 +686,10 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
|
||||
#endif
|
||||
__ sldi(size, size, Interpreter::logStackElementSize);
|
||||
__ add(R15_esp, R15_esp, size);
|
||||
|
||||
__ check_and_handle_popframe(R11_scratch1);
|
||||
__ check_and_handle_earlyret(R11_scratch1);
|
||||
|
||||
__ dispatch_next(state, step);
|
||||
return entry;
|
||||
}
|
||||
@ -1894,7 +1892,7 @@ address TemplateInterpreterGenerator::generate_CRC32_update_entry() {
|
||||
__ lwz(crc, 2*wordSize, argP); // Current crc state, zero extend to 64 bit to have a clean register.
|
||||
|
||||
StubRoutines::ppc64::generate_load_crc_table_addr(_masm, table);
|
||||
__ kernel_crc32_singleByte(crc, data, dataLen, table, tmp);
|
||||
__ kernel_crc32_singleByte(crc, data, dataLen, table, tmp, true);
|
||||
|
||||
// Restore caller sp for c2i case and return.
|
||||
__ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started.
|
||||
@ -1910,6 +1908,10 @@ address TemplateInterpreterGenerator::generate_CRC32_update_entry() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// TODO: generate_CRC32_updateBytes_entry and generate_CRC32C_updateBytes_entry are identical
|
||||
// except for using different crc tables and some block comment strings.
|
||||
// We should provide a common implementation.
|
||||
|
||||
// CRC32 Intrinsics.
|
||||
/**
|
||||
* Method entry for static native methods:
|
||||
@ -1986,7 +1988,7 @@ address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractI
|
||||
// Performance measurements show the 1word and 2word variants to be almost equivalent,
|
||||
// with very light advantages for the 1word variant. We chose the 1word variant for
|
||||
// code compactness.
|
||||
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, tc0, tc1, tc2, tc3);
|
||||
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, tc0, tc1, tc2, tc3, true);
|
||||
|
||||
// Restore caller sp for c2i case and return.
|
||||
__ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started.
|
||||
@ -2002,8 +2004,84 @@ address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractI
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Not supported
|
||||
// CRC32C Intrinsics.
|
||||
/**
|
||||
* Method entry for static native methods:
|
||||
* int java.util.zip.CRC32C.updateBytes( int crc, byte[] b, int off, int len)
|
||||
* int java.util.zip.CRC32C.updateDirectByteBuffer(int crc, long* buf, int off, int len)
|
||||
**/
|
||||
address TemplateInterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) {
|
||||
if (UseCRC32CIntrinsics) {
|
||||
address start = __ pc(); // Remember stub start address (is rtn value).
|
||||
|
||||
// We don't generate local frame and don't align stack because
|
||||
// we not even call stub code (we generate the code inline)
|
||||
// and there is no safepoint on this path.
|
||||
|
||||
// Load parameters.
|
||||
// Z_esp is callers operand stack pointer, i.e. it points to the parameters.
|
||||
const Register argP = R15_esp;
|
||||
const Register crc = R3_ARG1; // crc value
|
||||
const Register data = R4_ARG2; // address of java byte array
|
||||
const Register dataLen = R5_ARG3; // source data len
|
||||
const Register table = R6_ARG4; // address of crc32c table
|
||||
|
||||
const Register t0 = R9; // scratch registers for crc calculation
|
||||
const Register t1 = R10;
|
||||
const Register t2 = R11;
|
||||
const Register t3 = R12;
|
||||
|
||||
const Register tc0 = R2; // registers to hold pre-calculated column addresses
|
||||
const Register tc1 = R7;
|
||||
const Register tc2 = R8;
|
||||
const Register tc3 = table; // table address is reconstructed at the end of kernel_crc32_* emitters
|
||||
|
||||
const Register tmp = t0; // Only used very locally to calculate byte buffer address.
|
||||
|
||||
// Arguments are reversed on java expression stack.
|
||||
// Calculate address of start element.
|
||||
if (kind == Interpreter::java_util_zip_CRC32C_updateDirectByteBuffer) { // Used for "updateDirectByteBuffer".
|
||||
BLOCK_COMMENT("CRC32C_updateDirectByteBuffer {");
|
||||
// crc @ (SP + 5W) (32bit)
|
||||
// buf @ (SP + 3W) (64bit ptr to long array)
|
||||
// off @ (SP + 2W) (32bit)
|
||||
// dataLen @ (SP + 1W) (32bit)
|
||||
// data = buf + off
|
||||
__ ld( data, 3*wordSize, argP); // start of byte buffer
|
||||
__ lwa( tmp, 2*wordSize, argP); // byte buffer offset
|
||||
__ lwa( dataLen, 1*wordSize, argP); // #bytes to process
|
||||
__ lwz( crc, 5*wordSize, argP); // current crc state
|
||||
__ add( data, data, tmp); // Add byte buffer offset.
|
||||
} else { // Used for "updateBytes update".
|
||||
BLOCK_COMMENT("CRC32C_updateBytes {");
|
||||
// crc @ (SP + 4W) (32bit)
|
||||
// buf @ (SP + 3W) (64bit ptr to byte array)
|
||||
// off @ (SP + 2W) (32bit)
|
||||
// dataLen @ (SP + 1W) (32bit)
|
||||
// data = buf + off + base_offset
|
||||
__ ld( data, 3*wordSize, argP); // start of byte buffer
|
||||
__ lwa( tmp, 2*wordSize, argP); // byte buffer offset
|
||||
__ lwa( dataLen, 1*wordSize, argP); // #bytes to process
|
||||
__ add( data, data, tmp); // add byte buffer offset
|
||||
__ lwz( crc, 4*wordSize, argP); // current crc state
|
||||
__ addi(data, data, arrayOopDesc::base_offset_in_bytes(T_BYTE));
|
||||
}
|
||||
|
||||
StubRoutines::ppc64::generate_load_crc32c_table_addr(_masm, table);
|
||||
|
||||
// Performance measurements show the 1word and 2word variants to be almost equivalent,
|
||||
// with very light advantages for the 1word variant. We chose the 1word variant for
|
||||
// code compactness.
|
||||
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, tc0, tc1, tc2, tc3, false);
|
||||
|
||||
// Restore caller sp for c2i case and return.
|
||||
__ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started.
|
||||
__ blr();
|
||||
|
||||
BLOCK_COMMENT("} CRC32C_update{Bytes|DirectByteBuffer}");
|
||||
return start;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2017, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -172,18 +172,27 @@ void VM_Version::initialize() {
|
||||
|
||||
assert(AllocatePrefetchStyle >= 0, "AllocatePrefetchStyle should be positive");
|
||||
|
||||
// Implementation does not use any of the vector instructions
|
||||
// available with Power8. Their exploitation is still pending.
|
||||
// If defined(VM_LITTLE_ENDIAN) and running on Power8 or newer hardware,
|
||||
// the implementation uses the vector instructions available with Power8.
|
||||
// In all other cases, the implementation uses only generally available instructions.
|
||||
if (!UseCRC32Intrinsics) {
|
||||
if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseCRC32Intrinsics, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (UseCRC32CIntrinsics) {
|
||||
if (!FLAG_IS_DEFAULT(UseCRC32CIntrinsics))
|
||||
warning("CRC32C intrinsics are not available on this CPU");
|
||||
FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false);
|
||||
// Implementation does not use any of the vector instructions available with Power8.
|
||||
// Their exploitation is still pending (aka "work in progress").
|
||||
if (!UseCRC32CIntrinsics) {
|
||||
if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseCRC32CIntrinsics, true);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Provide implementation.
|
||||
if (UseAdler32Intrinsics) {
|
||||
warning("Adler32Intrinsics not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseAdler32Intrinsics, false);
|
||||
}
|
||||
|
||||
// The AES intrinsic stubs require AES instruction support.
|
||||
@ -245,11 +254,6 @@ void VM_Version::initialize() {
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
|
||||
}
|
||||
|
||||
if (UseAdler32Intrinsics) {
|
||||
warning("Adler32Intrinsics not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseAdler32Intrinsics, false);
|
||||
}
|
||||
|
||||
if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
|
||||
UseMultiplyToLenIntrinsic = true;
|
||||
}
|
||||
|
@ -28,8 +28,6 @@
|
||||
|
||||
#undef LUCY_DBG
|
||||
|
||||
#define NearLabel Label
|
||||
|
||||
// Immediate is an abstraction to represent the various immediate
|
||||
// operands which exist on z/Architecture. Neither this class nor
|
||||
// instances hereof have an own state. It consists of methods only.
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -3048,9 +3048,8 @@ void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) {
|
||||
assert_different_registers(val, crc, res);
|
||||
|
||||
__ load_const_optimized(res, StubRoutines::crc_table_addr());
|
||||
__ not_(crc, noreg, false); // ~crc
|
||||
__ update_byte_crc32(crc, val, res);
|
||||
__ not_(res, crc, false); // ~crc
|
||||
__ kernel_crc32_singleByteReg(crc, val, res, true);
|
||||
__ z_lgfr(res, crc);
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -61,20 +61,6 @@ void LIRItem::load_nonconstant(int bits) {
|
||||
}
|
||||
}
|
||||
|
||||
inline void load_int_as_long(LIR_List *ll, LIRItem &li, LIR_Opr dst) {
|
||||
LIR_Opr r = li.value()->operand();
|
||||
if (r->is_constant()) {
|
||||
// Constants get loaded with sign extend on this platform.
|
||||
ll->move(li.result(), dst);
|
||||
} else {
|
||||
if (!r->is_register()) {
|
||||
li.load_item_force(dst);
|
||||
}
|
||||
LIR_Opr dst_l = FrameMap::as_long_opr(dst->as_register());
|
||||
ll->convert(Bytecodes::_i2l, li.result(), dst_l); // Convert.
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// LIRGenerator
|
||||
//--------------------------------------------------------------
|
||||
@ -1217,10 +1203,9 @@ void LIRGenerator::do_update_CRC32(Intrinsic* x) {
|
||||
LIR_Opr arg2 = cc->at(1);
|
||||
LIR_Opr arg3 = cc->at(2);
|
||||
|
||||
// CCallingConventionRequiresIntsAsLongs
|
||||
crc.load_item_force(arg1); // We skip int->long conversion here, because CRC32 stub doesn't care about high bits.
|
||||
__ leal(LIR_OprFact::address(a), arg2);
|
||||
load_int_as_long(gen()->lir(), len, arg3);
|
||||
len.load_item_force(arg3); // We skip int->long conversion here, because CRC32 stub expects int.
|
||||
|
||||
__ call_runtime_leaf(StubRoutines::updateBytesCRC32(), LIR_OprFact::illegalOpr, result_reg, cc->args());
|
||||
__ move(result_reg, result);
|
||||
@ -1233,7 +1218,60 @@ void LIRGenerator::do_update_CRC32(Intrinsic* x) {
|
||||
}
|
||||
|
||||
void LIRGenerator::do_update_CRC32C(Intrinsic* x) {
|
||||
Unimplemented();
|
||||
assert(UseCRC32CIntrinsics, "or should not be here");
|
||||
LIR_Opr result = rlock_result(x);
|
||||
|
||||
switch (x->id()) {
|
||||
case vmIntrinsics::_updateBytesCRC32C:
|
||||
case vmIntrinsics::_updateDirectByteBufferCRC32C: {
|
||||
bool is_updateBytes = (x->id() == vmIntrinsics::_updateBytesCRC32C);
|
||||
|
||||
LIRItem crc(x->argument_at(0), this);
|
||||
LIRItem buf(x->argument_at(1), this);
|
||||
LIRItem off(x->argument_at(2), this);
|
||||
LIRItem len(x->argument_at(3), this);
|
||||
buf.load_item();
|
||||
off.load_nonconstant();
|
||||
|
||||
LIR_Opr index = off.result();
|
||||
int offset = is_updateBytes ? arrayOopDesc::base_offset_in_bytes(T_BYTE) : 0;
|
||||
if (off.result()->is_constant()) {
|
||||
index = LIR_OprFact::illegalOpr;
|
||||
offset += off.result()->as_jint();
|
||||
}
|
||||
LIR_Opr base_op = buf.result();
|
||||
|
||||
if (index->is_valid()) {
|
||||
LIR_Opr tmp = new_register(T_LONG);
|
||||
__ convert(Bytecodes::_i2l, index, tmp);
|
||||
index = tmp;
|
||||
}
|
||||
|
||||
LIR_Address* a = new LIR_Address(base_op, index, offset, T_BYTE);
|
||||
|
||||
BasicTypeList signature(3);
|
||||
signature.append(T_INT);
|
||||
signature.append(T_ADDRESS);
|
||||
signature.append(T_INT);
|
||||
CallingConvention* cc = frame_map()->c_calling_convention(&signature);
|
||||
const LIR_Opr result_reg = result_register_for (x->type());
|
||||
|
||||
LIR_Opr arg1 = cc->at(0);
|
||||
LIR_Opr arg2 = cc->at(1);
|
||||
LIR_Opr arg3 = cc->at(2);
|
||||
|
||||
crc.load_item_force(arg1); // We skip int->long conversion here, because CRC32C stub doesn't care about high bits.
|
||||
__ leal(LIR_OprFact::address(a), arg2);
|
||||
len.load_item_force(arg3); // We skip int->long conversion here, because CRC32C stub expects int.
|
||||
|
||||
__ call_runtime_leaf(StubRoutines::updateBytesCRC32C(), LIR_OprFact::illegalOpr, result_reg, cc->args());
|
||||
__ move(result_reg, result);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) {
|
||||
@ -1264,4 +1302,3 @@ void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) {
|
||||
void LIRGenerator::do_vectorizedMismatch(Intrinsic* x) {
|
||||
fatal("vectorizedMismatch intrinsic is not implemented on this platform");
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -48,9 +48,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
bool allow_relocation,
|
||||
bool check_exceptions);
|
||||
|
||||
virtual void check_and_handle_popframe(Register java_thread);
|
||||
virtual void check_and_handle_earlyret(Register java_thread);
|
||||
|
||||
// Base routine for all dispatches.
|
||||
void dispatch_base(TosState state, address* table);
|
||||
|
||||
@ -58,6 +55,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
InterpreterMacroAssembler(CodeBuffer* c)
|
||||
: MacroAssembler(c) {}
|
||||
|
||||
virtual void check_and_handle_popframe(Register java_thread);
|
||||
virtual void check_and_handle_earlyret(Register java_thread);
|
||||
|
||||
void jump_to_entry(address entry, Register Rscratch);
|
||||
|
||||
virtual void load_earlyret_value(TosState state);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -1616,6 +1616,8 @@ void MacroAssembler::branch_optimized(Assembler::branch_condition cond, Label& b
|
||||
if (branch_target.is_bound()) {
|
||||
address branch_addr = target(branch_target);
|
||||
branch_optimized(cond, branch_addr);
|
||||
} else if (branch_target.is_near()) {
|
||||
z_brc(cond, branch_target); // Caller assures that the target will be in range for z_brc.
|
||||
} else {
|
||||
z_brcl(cond, branch_target); // Let's hope target is in range. Otherwise, we will abort at patch time.
|
||||
}
|
||||
@ -1674,7 +1676,8 @@ void MacroAssembler::compare_and_branch_optimized(Register r1,
|
||||
bool has_sign) {
|
||||
address branch_origin = pc();
|
||||
bool x2_imm8 = (has_sign && Immediate::is_simm8(x2)) || (!has_sign && Immediate::is_uimm8(x2));
|
||||
bool is_RelAddr16 = (branch_target.is_bound() &&
|
||||
bool is_RelAddr16 = branch_target.is_near() ||
|
||||
(branch_target.is_bound() &&
|
||||
RelAddr::is_in_range_of_RelAddr16(target(branch_target), branch_origin));
|
||||
unsigned int casenum = (len64?2:0)+(has_sign?0:1);
|
||||
|
||||
@ -1744,13 +1747,21 @@ void MacroAssembler::compare_and_branch_optimized(Register r1,
|
||||
Label& branch_target,
|
||||
bool len64,
|
||||
bool has_sign) {
|
||||
unsigned int casenum = (len64?2:0)+(has_sign?0:1);
|
||||
unsigned int casenum = (len64 ? 2 : 0) + (has_sign ? 0 : 1);
|
||||
|
||||
if (branch_target.is_bound()) {
|
||||
address branch_addr = target(branch_target);
|
||||
compare_and_branch_optimized(r1, r2, cond, branch_addr, len64, has_sign);
|
||||
} else {
|
||||
{
|
||||
if (VM_Version::has_CompareBranch() && branch_target.is_near()) {
|
||||
switch (casenum) {
|
||||
case 0: z_crj( r1, r2, cond, branch_target); break;
|
||||
case 1: z_clrj( r1, r2, cond, branch_target); break;
|
||||
case 2: z_cgrj( r1, r2, cond, branch_target); break;
|
||||
case 3: z_clgrj(r1, r2, cond, branch_target); break;
|
||||
default: ShouldNotReachHere(); break;
|
||||
}
|
||||
} else {
|
||||
switch (casenum) {
|
||||
case 0: z_cr( r1, r2); break;
|
||||
case 1: z_clr(r1, r2); break;
|
||||
@ -2741,11 +2752,11 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
BLOCK_COMMENT("lookup_interface_method {");
|
||||
|
||||
// Load start of itable entries into itable_entry_addr.
|
||||
z_llgf(vtable_len, Address(recv_klass, InstanceKlass::vtable_length_offset()));
|
||||
z_llgf(vtable_len, Address(recv_klass, Klass::vtable_length_offset()));
|
||||
z_sllg(vtable_len, vtable_len, exact_log2(vtableEntry::size_in_bytes()));
|
||||
|
||||
// Loop over all itable entries until desired interfaceOop(Rinterface) found.
|
||||
const int vtable_base_offset = in_bytes(InstanceKlass::vtable_start_offset());
|
||||
const int vtable_base_offset = in_bytes(Klass::vtable_start_offset());
|
||||
|
||||
add2reg_with_index(itable_entry_addr,
|
||||
vtable_base_offset + itableOffsetEntry::interface_offset_in_bytes(),
|
||||
@ -5927,8 +5938,7 @@ void MacroAssembler::update_byte_crc32(Register crc, Register val, Register tabl
|
||||
* @param len register containing number of bytes
|
||||
* @param table register pointing to CRC table
|
||||
*/
|
||||
void MacroAssembler::update_byteLoop_crc32(Register crc, Register buf, Register len, Register table,
|
||||
Register data, bool invertCRC) {
|
||||
void MacroAssembler::update_byteLoop_crc32(Register crc, Register buf, Register len, Register table, Register data) {
|
||||
assert_different_registers(crc, buf, len, table, data);
|
||||
|
||||
Label L_mainLoop, L_done;
|
||||
@ -5938,20 +5948,12 @@ void MacroAssembler::update_byteLoop_crc32(Register crc, Register buf, Register
|
||||
z_ltr(len, len);
|
||||
z_brnh(L_done);
|
||||
|
||||
if (invertCRC) {
|
||||
not_(crc, noreg, false); // ~c
|
||||
}
|
||||
|
||||
bind(L_mainLoop);
|
||||
z_llgc(data, Address(buf, (intptr_t)0));// Current byte of input buffer (zero extended). Avoids garbage in upper half of register.
|
||||
add2reg(buf, mainLoop_stepping); // Advance buffer position.
|
||||
update_byte_crc32(crc, data, table);
|
||||
z_brct(len, L_mainLoop); // Iterate.
|
||||
|
||||
if (invertCRC) {
|
||||
not_(crc, noreg, false); // ~c
|
||||
}
|
||||
|
||||
bind(L_done);
|
||||
}
|
||||
|
||||
@ -5968,6 +5970,7 @@ void MacroAssembler::update_1word_crc32(Register crc, Register buf, Register tab
|
||||
// c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
|
||||
// crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
|
||||
// #define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
|
||||
// Pre-calculate (constant) column offsets, use columns 4..7 for big-endian.
|
||||
const int ix0 = 4*(4*CRC32_COLUMN_SIZE);
|
||||
const int ix1 = 5*(4*CRC32_COLUMN_SIZE);
|
||||
const int ix2 = 6*(4*CRC32_COLUMN_SIZE);
|
||||
@ -5986,17 +5989,12 @@ void MacroAssembler::update_1word_crc32(Register crc, Register buf, Register tab
|
||||
rotate_then_insert(t1, t0, 56-2, 63-2, 2-16, true); // ((c >> 16) & 0xff) << 2
|
||||
rotate_then_insert(t0, t0, 56-2, 63-2, 2-24, true); // ((c >> 24) & 0xff) << 2
|
||||
|
||||
// Load pre-calculated table values.
|
||||
// Use columns 4..7 for big-endian.
|
||||
z_ly(t3, Address(table, t3, (intptr_t)ix0));
|
||||
// XOR indexed table values to calculate updated crc.
|
||||
z_ly(t2, Address(table, t2, (intptr_t)ix1));
|
||||
z_ly(t1, Address(table, t1, (intptr_t)ix2));
|
||||
z_ly(t0, Address(table, t0, (intptr_t)ix3));
|
||||
|
||||
// Calculate new crc from table values.
|
||||
z_xr(t2, t3);
|
||||
z_xr(t0, t1);
|
||||
z_xr(t0, t2); // Now crc contains the final checksum value.
|
||||
z_xy(t2, Address(table, t3, (intptr_t)ix0));
|
||||
z_xy(t0, Address(table, t1, (intptr_t)ix2));
|
||||
z_xr(t0, t2); // Now t0 contains the updated CRC value.
|
||||
lgr_if_needed(crc, t0);
|
||||
}
|
||||
|
||||
@ -6009,7 +6007,8 @@ void MacroAssembler::update_1word_crc32(Register crc, Register buf, Register tab
|
||||
* uses Z_R10..Z_R13 as work register. Must be saved/restored by caller!
|
||||
*/
|
||||
void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len, Register table,
|
||||
Register t0, Register t1, Register t2, Register t3) {
|
||||
Register t0, Register t1, Register t2, Register t3,
|
||||
bool invertCRC) {
|
||||
assert_different_registers(crc, buf, len, table);
|
||||
|
||||
Label L_mainLoop, L_tail;
|
||||
@ -6024,7 +6023,9 @@ void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len
|
||||
// The situation itself is detected and handled correctly by the conditional branches
|
||||
// following aghi(len, -stepping) and aghi(len, +stepping).
|
||||
|
||||
not_(crc, noreg, false); // 1s complement of crc
|
||||
if (invertCRC) {
|
||||
not_(crc, noreg, false); // 1s complement of crc
|
||||
}
|
||||
|
||||
#if 0
|
||||
{
|
||||
@ -6039,7 +6040,7 @@ void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len
|
||||
rotate_then_insert(ctr, ctr, 62, 63, 0, true); // TODO: should set cc
|
||||
z_sgfr(len, ctr); // Remaining len after alignment.
|
||||
|
||||
update_byteLoop_crc32(crc, buf, ctr, table, data, false);
|
||||
update_byteLoop_crc32(crc, buf, ctr, table, data);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -6047,21 +6048,23 @@ void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len
|
||||
z_srag(ctr, len, log_stepping);
|
||||
z_brnh(L_tail);
|
||||
|
||||
z_lrvr(crc, crc); // Revert byte order because we are dealing with big-endian data.
|
||||
z_lrvr(crc, crc); // Revert byte order because we are dealing with big-endian data.
|
||||
rotate_then_insert(len, len, 64-log_stepping, 63, 0, true); // #bytes for tailLoop
|
||||
|
||||
BIND(L_mainLoop);
|
||||
update_1word_crc32(crc, buf, table, 0, 0, crc, t1, t2, t3);
|
||||
update_1word_crc32(crc, buf, table, 4, mainLoop_stepping, crc, t1, t2, t3);
|
||||
z_brct(ctr, L_mainLoop); // Iterate.
|
||||
z_brct(ctr, L_mainLoop); // Iterate.
|
||||
|
||||
z_lrvr(crc, crc); // Revert byte order back to original.
|
||||
z_lrvr(crc, crc); // Revert byte order back to original.
|
||||
|
||||
// Process last few (<8) bytes of buffer.
|
||||
BIND(L_tail);
|
||||
update_byteLoop_crc32(crc, buf, len, table, data, false);
|
||||
update_byteLoop_crc32(crc, buf, len, table, data);
|
||||
|
||||
not_(crc, noreg, false); // 1s complement of crc
|
||||
if (invertCRC) {
|
||||
not_(crc, noreg, false); // 1s complement of crc
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -6073,7 +6076,8 @@ void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len
|
||||
* uses Z_R10..Z_R13 as work register. Must be saved/restored by caller!
|
||||
*/
|
||||
void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len, Register table,
|
||||
Register t0, Register t1, Register t2, Register t3) {
|
||||
Register t0, Register t1, Register t2, Register t3,
|
||||
bool invertCRC) {
|
||||
assert_different_registers(crc, buf, len, table);
|
||||
|
||||
Label L_mainLoop, L_tail;
|
||||
@ -6087,7 +6091,9 @@ void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len
|
||||
// The situation itself is detected and handled correctly by the conditional branches
|
||||
// following aghi(len, -stepping) and aghi(len, +stepping).
|
||||
|
||||
not_(crc, noreg, false); // 1s complement of crc
|
||||
if (invertCRC) {
|
||||
not_(crc, noreg, false); // 1s complement of crc
|
||||
}
|
||||
|
||||
// Check for short (<4 bytes) buffer.
|
||||
z_srag(ctr, len, log_stepping);
|
||||
@ -6099,13 +6105,16 @@ void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len
|
||||
BIND(L_mainLoop);
|
||||
update_1word_crc32(crc, buf, table, 0, mainLoop_stepping, crc, t1, t2, t3);
|
||||
z_brct(ctr, L_mainLoop); // Iterate.
|
||||
|
||||
z_lrvr(crc, crc); // Revert byte order back to original.
|
||||
|
||||
// Process last few (<8) bytes of buffer.
|
||||
BIND(L_tail);
|
||||
update_byteLoop_crc32(crc, buf, len, table, data, false);
|
||||
update_byteLoop_crc32(crc, buf, len, table, data);
|
||||
|
||||
not_(crc, noreg, false); // 1s complement of crc
|
||||
if (invertCRC) {
|
||||
not_(crc, noreg, false); // 1s complement of crc
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -6115,22 +6124,51 @@ void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len
|
||||
* @param table register pointing to CRC table
|
||||
*/
|
||||
void MacroAssembler::kernel_crc32_1byte(Register crc, Register buf, Register len, Register table,
|
||||
Register t0, Register t1, Register t2, Register t3) {
|
||||
Register t0, Register t1, Register t2, Register t3,
|
||||
bool invertCRC) {
|
||||
assert_different_registers(crc, buf, len, table);
|
||||
Register data = t0;
|
||||
|
||||
update_byteLoop_crc32(crc, buf, len, table, data, true);
|
||||
if (invertCRC) {
|
||||
not_(crc, noreg, false); // 1s complement of crc
|
||||
}
|
||||
|
||||
update_byteLoop_crc32(crc, buf, len, table, data);
|
||||
|
||||
if (invertCRC) {
|
||||
not_(crc, noreg, false); // 1s complement of crc
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::kernel_crc32_singleByte(Register crc, Register buf, Register len, Register table, Register tmp) {
|
||||
void MacroAssembler::kernel_crc32_singleByte(Register crc, Register buf, Register len, Register table, Register tmp,
|
||||
bool invertCRC) {
|
||||
assert_different_registers(crc, buf, len, table, tmp);
|
||||
|
||||
not_(crc, noreg, false); // ~c
|
||||
if (invertCRC) {
|
||||
not_(crc, noreg, false); // 1s complement of crc
|
||||
}
|
||||
|
||||
z_llgc(tmp, Address(buf, (intptr_t)0)); // Current byte of input buffer (zero extended). Avoids garbage in upper half of register.
|
||||
update_byte_crc32(crc, tmp, table);
|
||||
|
||||
not_(crc, noreg, false); // ~c
|
||||
if (invertCRC) {
|
||||
not_(crc, noreg, false); // 1s complement of crc
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::kernel_crc32_singleByteReg(Register crc, Register val, Register table,
|
||||
bool invertCRC) {
|
||||
assert_different_registers(crc, val, table);
|
||||
|
||||
if (invertCRC) {
|
||||
not_(crc, noreg, false); // 1s complement of crc
|
||||
}
|
||||
|
||||
update_byte_crc32(crc, val, table);
|
||||
|
||||
if (invertCRC) {
|
||||
not_(crc, noreg, false); // 1s complement of crc
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -1011,22 +1011,35 @@ class MacroAssembler: public Assembler {
|
||||
int before = 0, int after = 0) PRODUCT_RETURN;
|
||||
|
||||
// Emitters for CRC32 calculation.
|
||||
// A note on invertCRC:
|
||||
// Unfortunately, internal representation of crc differs between CRC32 and CRC32C.
|
||||
// CRC32 holds it's current crc value in the externally visible representation.
|
||||
// CRC32C holds it's current crc value in internal format, ready for updating.
|
||||
// Thus, the crc value must be bit-flipped before updating it in the CRC32 case.
|
||||
// In the CRC32C case, it must be bit-flipped when it is given to the outside world (getValue()).
|
||||
// The bool invertCRC parameter indicates whether bit-flipping is required before updates.
|
||||
private:
|
||||
void fold_byte_crc32(Register crc, Register table, Register val, Register tmp);
|
||||
void fold_8bit_crc32(Register crc, Register table, Register tmp);
|
||||
void update_byte_crc32( Register crc, Register val, Register table);
|
||||
void update_byteLoop_crc32(Register crc, Register buf, Register len, Register table,
|
||||
Register data, bool invertCRC);
|
||||
Register data);
|
||||
void update_1word_crc32(Register crc, Register buf, Register table, int bufDisp, int bufInc,
|
||||
Register t0, Register t1, Register t2, Register t3);
|
||||
public:
|
||||
void update_byte_crc32( Register crc, Register val, Register table);
|
||||
void kernel_crc32_singleByte(Register crc, Register buf, Register len, Register table, Register tmp);
|
||||
void kernel_crc32_singleByteReg(Register crc, Register val, Register table,
|
||||
bool invertCRC);
|
||||
void kernel_crc32_singleByte(Register crc, Register buf, Register len, Register table, Register tmp,
|
||||
bool invertCRC);
|
||||
void kernel_crc32_1byte(Register crc, Register buf, Register len, Register table,
|
||||
Register t0, Register t1, Register t2, Register t3);
|
||||
Register t0, Register t1, Register t2, Register t3,
|
||||
bool invertCRC);
|
||||
void kernel_crc32_1word(Register crc, Register buf, Register len, Register table,
|
||||
Register t0, Register t1, Register t2, Register t3);
|
||||
Register t0, Register t1, Register t2, Register t3,
|
||||
bool invertCRC);
|
||||
void kernel_crc32_2word(Register crc, Register buf, Register len, Register table,
|
||||
Register t0, Register t1, Register t2, Register t3);
|
||||
Register t0, Register t1, Register t2, Register t3,
|
||||
bool invertCRC);
|
||||
|
||||
// Emitters for BigInteger.multiplyToLen intrinsic
|
||||
// note: length of result array (zlen) is passed on the stack
|
||||
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/codeBuffer.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
|
||||
// Generate the self-patching vtable method:
|
||||
//
|
||||
// This method will be called (as any other Klass virtual method) with
|
||||
// the Klass itself as the first argument. Example:
|
||||
//
|
||||
// oop obj;
|
||||
// int size = obj->klass()->klass_part()->oop_size(this);
|
||||
//
|
||||
// for which the virtual method call is Klass::oop_size();.
|
||||
//
|
||||
// The dummy method is called with the Klass object as the first
|
||||
// operand, and an object as the second argument.
|
||||
//
|
||||
|
||||
//=====================================================================
|
||||
|
||||
// All of the dummy methods in the vtable are essentially identical,
|
||||
// differing only by an ordinal constant, and they bear no releationship
|
||||
// to the original method which the caller intended. Also, there needs
|
||||
// to be 'vtbl_list_size' instances of the vtable in order to
|
||||
// differentiate between the 'vtable_list_size' original Klass objects.
|
||||
|
||||
#undef __
|
||||
#define __ masm->
|
||||
|
||||
void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
|
||||
void** vtable,
|
||||
char** md_top,
|
||||
char* md_end,
|
||||
char** mc_top,
|
||||
char* mc_end) {
|
||||
|
||||
intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
|
||||
*(intptr_t *)(*md_top) = vtable_bytes;
|
||||
*md_top += sizeof(intptr_t);
|
||||
void** dummy_vtable = (void**)*md_top;
|
||||
*vtable = dummy_vtable;
|
||||
*md_top += vtable_bytes;
|
||||
|
||||
// Get ready to generate dummy methods.
|
||||
|
||||
CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
|
||||
MacroAssembler* masm = new MacroAssembler(&cb);
|
||||
|
||||
__ unimplemented();
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -73,7 +73,7 @@ void MethodHandles::verify_klass(MacroAssembler* _masm,
|
||||
const char* error_message) {
|
||||
|
||||
InstanceKlass** klass_addr = SystemDictionary::well_known_klass_addr(klass_id);
|
||||
KlassHandle klass = SystemDictionary::well_known_klass(klass_id);
|
||||
Klass* klass = SystemDictionary::well_known_klass(klass_id);
|
||||
|
||||
assert(temp_reg != Z_R0 && // Is used as base register!
|
||||
temp_reg != noreg && temp2_reg != noreg, "need valid registers!");
|
||||
|
@ -6768,6 +6768,7 @@ instruct sllI_reg_imm(iRegI dst, iRegI src, immI nbits) %{
|
||||
format %{ "SLL $dst,$src,$nbits\t# use RISC-like SLLG also for int" %}
|
||||
ins_encode %{
|
||||
int Nbit = $nbits$$constant;
|
||||
assert((Nbit & (BitsPerJavaInteger - 1)) == Nbit, "Check shift mask in ideal graph");
|
||||
__ z_sllg($dst$$Register, $src$$Register, Nbit & (BitsPerJavaInteger - 1), Z_R0);
|
||||
%}
|
||||
ins_pipe(pipe_class_dummy);
|
||||
@ -6841,6 +6842,7 @@ instruct sraI_reg_imm(iRegI dst, immI src, flagsReg cr) %{
|
||||
format %{ "SRA $dst,$src" %}
|
||||
ins_encode %{
|
||||
int Nbit = $src$$constant;
|
||||
assert((Nbit & (BitsPerJavaInteger - 1)) == Nbit, "Check shift mask in ideal graph");
|
||||
__ z_sra($dst$$Register, Nbit & (BitsPerJavaInteger - 1), Z_R0);
|
||||
%}
|
||||
ins_pipe(pipe_class_dummy);
|
||||
@ -6893,6 +6895,7 @@ instruct srlI_reg_imm(iRegI dst, immI src) %{
|
||||
format %{ "SRL $dst,$src" %}
|
||||
ins_encode %{
|
||||
int Nbit = $src$$constant;
|
||||
assert((Nbit & (BitsPerJavaInteger - 1)) == Nbit, "Check shift mask in ideal graph");
|
||||
__ z_srl($dst$$Register, Nbit & (BitsPerJavaInteger - 1), Z_R0);
|
||||
%}
|
||||
ins_pipe(pipe_class_dummy);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -623,26 +623,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||
#define __ (Verbose ? (_masm->block_comment(FILE_AND_LINE),_masm):_masm)->
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// The following routine generates a subroutine to throw an asynchronous
|
||||
// UnknownError when an unsafe access gets a fault that could not be
|
||||
// reasonably prevented by the programmer. (Example: SIGBUS/OBJERR.)
|
||||
//
|
||||
// Arguments:
|
||||
// trapping PC: ??
|
||||
//
|
||||
// Results:
|
||||
// Posts an asynchronous exception, skips the trapping instruction.
|
||||
//
|
||||
address generate_handler_for_unsafe_access() {
|
||||
StubCodeMark mark(this, "StubRoutines", "handler_for_unsafe_access");
|
||||
{
|
||||
address start = __ pc();
|
||||
__ unimplemented("StubRoutines::handler_for_unsafe_access", 86);
|
||||
return start;
|
||||
}
|
||||
}
|
||||
|
||||
// Support for uint StubRoutine::zarch::partial_subtype_check(Klass
|
||||
// sub, Klass super);
|
||||
//
|
||||
@ -2330,26 +2310,25 @@ class StubGenerator: public StubCodeGenerator {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Arguments:
|
||||
// Z_ARG1 - int crc
|
||||
// Z_ARG2 - byte* buf
|
||||
// Z_ARG3 - int length (of buffer)
|
||||
//
|
||||
// Result:
|
||||
// Z_RET - int crc result
|
||||
//
|
||||
// Compute CRC32 function.
|
||||
address generate_CRC32_updateBytes(const char* name) {
|
||||
__ align(CodeEntryAlignment);
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
unsigned int start_off = __ offset(); // Remember stub start address (is rtn value).
|
||||
/**
|
||||
* Arguments:
|
||||
*
|
||||
* Inputs:
|
||||
* Z_ARG1 - int crc
|
||||
* Z_ARG2 - byte* buf
|
||||
* Z_ARG3 - int length (of buffer)
|
||||
*
|
||||
* Result:
|
||||
* Z_RET - int crc result
|
||||
**/
|
||||
// Compute CRC function (generic, for all polynomials).
|
||||
void generate_CRC_updateBytes(const char* name, Register table, bool invertCRC) {
|
||||
|
||||
// arguments to kernel_crc32:
|
||||
Register crc = Z_ARG1; // Current checksum, preset by caller or result from previous call, int.
|
||||
Register data = Z_ARG2; // source byte array
|
||||
Register dataLen = Z_ARG3; // #bytes to process, int
|
||||
Register table = Z_ARG4; // crc table address
|
||||
// Register table = Z_ARG4; // crc table address. Preloaded and passed in by caller.
|
||||
const Register t0 = Z_R10; // work reg for kernel* emitters
|
||||
const Register t1 = Z_R11; // work reg for kernel* emitters
|
||||
const Register t2 = Z_R12; // work reg for kernel* emitters
|
||||
@ -2361,16 +2340,50 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// Crc used as int.
|
||||
__ z_llgfr(dataLen, dataLen);
|
||||
|
||||
StubRoutines::zarch::generate_load_crc_table_addr(_masm, table);
|
||||
|
||||
__ resize_frame(-(6*8), Z_R0, true); // Resize frame to provide add'l space to spill 5 registers.
|
||||
__ z_stmg(Z_R10, Z_R13, 1*8, Z_SP); // Spill regs 10..11 to make them available as work registers.
|
||||
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3);
|
||||
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, invertCRC);
|
||||
__ z_lmg(Z_R10, Z_R13, 1*8, Z_SP); // Spill regs 10..11 back from stack.
|
||||
__ resize_frame(+(6*8), Z_R0, true); // Resize frame to provide add'l space to spill 5 registers.
|
||||
|
||||
__ z_llgfr(Z_RET, crc); // Updated crc is function result. No copying required, just zero upper 32 bits.
|
||||
__ z_br(Z_R14); // Result already in Z_RET == Z_ARG1.
|
||||
}
|
||||
|
||||
|
||||
// Compute CRC32 function.
|
||||
address generate_CRC32_updateBytes(const char* name) {
|
||||
__ align(CodeEntryAlignment);
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
unsigned int start_off = __ offset(); // Remember stub start address (is rtn value).
|
||||
|
||||
assert(UseCRC32Intrinsics, "should not generate this stub (%s) with CRC32 intrinsics disabled", name);
|
||||
|
||||
BLOCK_COMMENT("CRC32_updateBytes {");
|
||||
Register table = Z_ARG4; // crc32 table address.
|
||||
StubRoutines::zarch::generate_load_crc_table_addr(_masm, table);
|
||||
|
||||
generate_CRC_updateBytes(name, table, true);
|
||||
BLOCK_COMMENT("} CRC32_updateBytes");
|
||||
|
||||
return __ addr_at(start_off);
|
||||
}
|
||||
|
||||
|
||||
// Compute CRC32C function.
|
||||
address generate_CRC32C_updateBytes(const char* name) {
|
||||
__ align(CodeEntryAlignment);
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
unsigned int start_off = __ offset(); // Remember stub start address (is rtn value).
|
||||
|
||||
assert(UseCRC32CIntrinsics, "should not generate this stub (%s) with CRC32C intrinsics disabled", name);
|
||||
|
||||
BLOCK_COMMENT("CRC32C_updateBytes {");
|
||||
Register table = Z_ARG4; // crc32c table address.
|
||||
StubRoutines::zarch::generate_load_crc32c_table_addr(_masm, table);
|
||||
|
||||
generate_CRC_updateBytes(name, table, false);
|
||||
BLOCK_COMMENT("} CRC32C_updateBytes");
|
||||
|
||||
return __ addr_at(start_off);
|
||||
}
|
||||
@ -2441,9 +2454,13 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// Entry points that are platform specific.
|
||||
|
||||
if (UseCRC32Intrinsics) {
|
||||
// We have no CRC32 table on z/Architecture.
|
||||
StubRoutines::_crc_table_adr = (address)StubRoutines::zarch::_crc_table;
|
||||
StubRoutines::_updateBytesCRC32 = generate_CRC32_updateBytes("CRC32_updateBytes");
|
||||
StubRoutines::_crc_table_adr = (address)StubRoutines::zarch::_crc_table;
|
||||
StubRoutines::_updateBytesCRC32 = generate_CRC32_updateBytes("CRC32_updateBytes");
|
||||
}
|
||||
|
||||
if (UseCRC32CIntrinsics) {
|
||||
StubRoutines::_crc32c_table_addr = (address)StubRoutines::zarch::_crc32c_table;
|
||||
StubRoutines::_updateBytesCRC32C = generate_CRC32C_updateBytes("CRC32C_updateBytes");
|
||||
}
|
||||
|
||||
// Comapct string intrinsics: Translate table for string inflate intrinsic. Used by trot instruction.
|
||||
@ -2461,8 +2478,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false);
|
||||
StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call), false);
|
||||
|
||||
StubRoutines::zarch::_handler_for_unsafe_access_entry = generate_handler_for_unsafe_access();
|
||||
|
||||
// Support for verify_oop (must happen after universe_init).
|
||||
StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop_subroutine();
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -68,12 +68,11 @@ class zarch {
|
||||
};
|
||||
|
||||
private:
|
||||
static address _handler_for_unsafe_access_entry;
|
||||
|
||||
static int _atomic_memory_operation_lock;
|
||||
|
||||
static address _partial_subtype_check;
|
||||
static juint _crc_table[CRC32_TABLES][CRC32_COLUMN_SIZE];
|
||||
static juint _crc32c_table[CRC32_TABLES][CRC32_COLUMN_SIZE];
|
||||
|
||||
// Comapct string intrinsics: Translate table for string inflate intrinsic. Used by trot instruction.
|
||||
static address _trot_table_addr;
|
||||
@ -91,11 +90,11 @@ class zarch {
|
||||
static int atomic_memory_operation_lock() { return _atomic_memory_operation_lock; }
|
||||
static void set_atomic_memory_operation_lock(int value) { _atomic_memory_operation_lock = value; }
|
||||
|
||||
static address handler_for_unsafe_access_entry() { return _handler_for_unsafe_access_entry; }
|
||||
|
||||
static address partial_subtype_check() { return _partial_subtype_check; }
|
||||
|
||||
static void generate_load_absolute_address(MacroAssembler* masm, Register table, address table_addr, uint64_t table_contents);
|
||||
static void generate_load_crc_table_addr(MacroAssembler* masm, Register table);
|
||||
static void generate_load_crc32c_table_addr(MacroAssembler* masm, Register table);
|
||||
|
||||
// Comapct string intrinsics: Translate table for string inflate intrinsic. Used by trot instruction.
|
||||
static void generate_load_trot_table_addr(MacroAssembler* masm, Register table);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -642,13 +642,6 @@ address TemplateInterpreterGenerator::generate_exception_handler_common(const ch
|
||||
return entry;
|
||||
}
|
||||
|
||||
// Unused, should never pass by.
|
||||
address TemplateInterpreterGenerator::generate_continuation_for (TosState state) {
|
||||
address entry = __ pc();
|
||||
__ should_not_reach_here();
|
||||
return entry;
|
||||
}
|
||||
|
||||
address TemplateInterpreterGenerator::generate_return_entry_for (TosState state, int step, size_t index_size) {
|
||||
address entry = __ pc();
|
||||
|
||||
@ -683,6 +676,10 @@ address TemplateInterpreterGenerator::generate_return_entry_for (TosState state,
|
||||
__ z_llgc(size, Address(cache, offset, flags_offset+(sizeof(size_t)-1)));
|
||||
__ z_sllg(size, size, Interpreter::logStackElementSize); // Each argument size in bytes.
|
||||
__ z_agr(Z_esp, size); // Pop arguments.
|
||||
|
||||
__ check_and_handle_popframe(Z_thread);
|
||||
__ check_and_handle_earlyret(Z_thread);
|
||||
|
||||
__ dispatch_next(state, step);
|
||||
|
||||
BLOCK_COMMENT("} return_entry");
|
||||
@ -1964,7 +1961,7 @@ address TemplateInterpreterGenerator::generate_CRC32_update_entry() {
|
||||
__ z_llgf(crc, 2 * wordSize, argP); // Current crc state, zero extend to 64 bit to have a clean register.
|
||||
|
||||
StubRoutines::zarch::generate_load_crc_table_addr(_masm, table);
|
||||
__ kernel_crc32_singleByte(crc, data, dataLen, table, Z_R1);
|
||||
__ kernel_crc32_singleByte(crc, data, dataLen, table, Z_R1, true);
|
||||
|
||||
// Restore caller sp for c2i case.
|
||||
__ resize_frame_absolute(Z_R10, Z_R0, true); // Cut the stack back to where the caller started.
|
||||
@ -2020,10 +2017,10 @@ address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractI
|
||||
// data = buf + off
|
||||
BLOCK_COMMENT("CRC32_updateByteBuffer {");
|
||||
__ z_llgf(crc, 5*wordSize, argP); // current crc state
|
||||
__ z_lg(data, 3*wordSize, argP); // start of byte buffer
|
||||
__ z_lg(data, 3*wordSize, argP); // start of byte buffer
|
||||
__ z_agf(data, 2*wordSize, argP); // Add byte buffer offset.
|
||||
__ z_lgf(dataLen, 1*wordSize, argP); // #bytes to process
|
||||
} else { // Used for "updateBytes update".
|
||||
} else { // Used for "updateBytes update".
|
||||
// crc @ (SP + 4W) (32bit)
|
||||
// buf @ (SP + 3W) (64bit ptr to byte array)
|
||||
// off @ (SP + 2W) (32bit)
|
||||
@ -2031,7 +2028,7 @@ address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractI
|
||||
// data = buf + off + base_offset
|
||||
BLOCK_COMMENT("CRC32_updateBytes {");
|
||||
__ z_llgf(crc, 4*wordSize, argP); // current crc state
|
||||
__ z_lg(data, 3*wordSize, argP); // start of byte buffer
|
||||
__ z_lg(data, 3*wordSize, argP); // start of byte buffer
|
||||
__ z_agf(data, 2*wordSize, argP); // Add byte buffer offset.
|
||||
__ z_lgf(dataLen, 1*wordSize, argP); // #bytes to process
|
||||
__ z_aghi(data, arrayOopDesc::base_offset_in_bytes(T_BYTE));
|
||||
@ -2041,7 +2038,7 @@ address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractI
|
||||
|
||||
__ resize_frame(-(6*8), Z_R0, true); // Resize frame to provide add'l space to spill 5 registers.
|
||||
__ z_stmg(t0, t3, 1*8, Z_SP); // Spill regs 10..13 to make them available as work registers.
|
||||
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3);
|
||||
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, true);
|
||||
__ z_lmg(t0, t3, 1*8, Z_SP); // Spill regs 10..13 back from stack.
|
||||
|
||||
// Restore caller sp for c2i case.
|
||||
@ -2060,8 +2057,73 @@ address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractI
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Not supported
|
||||
|
||||
// Method entry for static native methods:
|
||||
// int java.util.zip.CRC32C.updateBytes(int crc, byte[] b, int off, int len)
|
||||
// int java.util.zip.CRC32C.updateDirectByteBuffer(int crc, long buf, int off, int len)
|
||||
address TemplateInterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) {
|
||||
|
||||
if (UseCRC32CIntrinsics) {
|
||||
uint64_t entry_off = __ offset();
|
||||
|
||||
// We don't generate local frame and don't align stack because
|
||||
// we call stub code and there is no safepoint on this path.
|
||||
|
||||
// Load parameters.
|
||||
// Z_esp is callers operand stack pointer, i.e. it points to the parameters.
|
||||
const Register argP = Z_esp;
|
||||
const Register crc = Z_ARG1; // crc value
|
||||
const Register data = Z_ARG2; // address of java byte array
|
||||
const Register dataLen = Z_ARG3; // source data len
|
||||
const Register table = Z_ARG4; // address of crc32 table
|
||||
const Register t0 = Z_R10; // work reg for kernel* emitters
|
||||
const Register t1 = Z_R11; // work reg for kernel* emitters
|
||||
const Register t2 = Z_R12; // work reg for kernel* emitters
|
||||
const Register t3 = Z_R13; // work reg for kernel* emitters
|
||||
|
||||
// Arguments are reversed on java expression stack.
|
||||
// Calculate address of start element.
|
||||
if (kind == Interpreter::java_util_zip_CRC32C_updateDirectByteBuffer) { // Used for "updateByteBuffer direct".
|
||||
// crc @ (SP + 5W) (32bit)
|
||||
// buf @ (SP + 3W) (64bit ptr to long array)
|
||||
// off @ (SP + 2W) (32bit)
|
||||
// dataLen @ (SP + 1W) (32bit)
|
||||
// data = buf + off
|
||||
BLOCK_COMMENT("CRC32C_updateDirectByteBuffer {");
|
||||
__ z_llgf(crc, 5*wordSize, argP); // current crc state
|
||||
__ z_lg(data, 3*wordSize, argP); // start of byte buffer
|
||||
__ z_agf(data, 2*wordSize, argP); // Add byte buffer offset.
|
||||
__ z_lgf(dataLen, 1*wordSize, argP); // #bytes to process
|
||||
} else { // Used for "updateBytes update".
|
||||
// crc @ (SP + 4W) (32bit)
|
||||
// buf @ (SP + 3W) (64bit ptr to byte array)
|
||||
// off @ (SP + 2W) (32bit)
|
||||
// dataLen @ (SP + 1W) (32bit)
|
||||
// data = buf + off + base_offset
|
||||
BLOCK_COMMENT("CRC32C_updateBytes {");
|
||||
__ z_llgf(crc, 4*wordSize, argP); // current crc state
|
||||
__ z_lg(data, 3*wordSize, argP); // start of byte buffer
|
||||
__ z_agf(data, 2*wordSize, argP); // Add byte buffer offset.
|
||||
__ z_lgf(dataLen, 1*wordSize, argP); // #bytes to process
|
||||
__ z_aghi(data, arrayOopDesc::base_offset_in_bytes(T_BYTE));
|
||||
}
|
||||
|
||||
StubRoutines::zarch::generate_load_crc32c_table_addr(_masm, table);
|
||||
|
||||
__ resize_frame(-(6*8), Z_R0, true); // Resize frame to provide add'l space to spill 5 registers.
|
||||
__ z_stmg(t0, t3, 1*8, Z_SP); // Spill regs 10..13 to make them available as work registers.
|
||||
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, false);
|
||||
__ z_lmg(t0, t3, 1*8, Z_SP); // Spill regs 10..13 back from stack.
|
||||
|
||||
// Restore caller sp for c2i case.
|
||||
__ resize_frame_absolute(Z_R10, Z_R0, true); // Cut the stack back to where the caller started.
|
||||
|
||||
__ z_br(Z_R14);
|
||||
|
||||
BLOCK_COMMENT("} CRC32C_update{Bytes|DirectByteBuffer}");
|
||||
return __ addr_at(entry_off);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -3466,7 +3466,7 @@ void TemplateTable::invokevirtual_helper(Register index,
|
||||
__ z_sllg(index, index, exact_log2(vtableEntry::size_in_bytes()));
|
||||
__ mem2reg_opt(method,
|
||||
Address(Z_tmp_2, index,
|
||||
InstanceKlass::vtable_start_offset() + in_ByteSize(vtableEntry::method_offset_in_bytes())));
|
||||
Klass::vtable_start_offset() + in_ByteSize(vtableEntry::method_offset_in_bytes())));
|
||||
__ profile_arguments_type(Z_ARG4, method, Z_ARG5, true);
|
||||
__ jump_from_interpreted(method, Z_ARG4);
|
||||
BLOCK_COMMENT("} invokevirtual_helper");
|
||||
|
@ -111,13 +111,23 @@ void VM_Version::initialize() {
|
||||
ContendedPaddingWidth = cache_line_size;
|
||||
}
|
||||
|
||||
// On z/Architecture, the CRC32 intrinsics had to be implemented "by hand".
|
||||
// They cannot be based on the CHECKSUM instruction which has been there
|
||||
// since the very beginning (of z/Architecture). It computes "some kind of" a checksum
|
||||
// which has nothing to do with the CRC32 algorithm.
|
||||
// On z/Architecture, the CRC32/CRC32C intrinsics are implemented "by hand".
|
||||
// TODO: Provide implementation based on the vector instructions available from z13.
|
||||
// Note: The CHECKSUM instruction, which has been there since the very beginning
|
||||
// (of z/Architecture), computes "some kind of" a checksum.
|
||||
// It has nothing to do with the CRC32 algorithm.
|
||||
if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseCRC32Intrinsics, true);
|
||||
}
|
||||
if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseCRC32CIntrinsics, true);
|
||||
}
|
||||
|
||||
// TODO: Provide implementation.
|
||||
if (UseAdler32Intrinsics) {
|
||||
warning("Adler32Intrinsics not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseAdler32Intrinsics, false);
|
||||
}
|
||||
|
||||
// On z/Architecture, we take UseAES as the general switch to enable/disable the AES intrinsics.
|
||||
// The specific, and yet to be defined, switches UseAESxxxIntrinsics will then be set
|
||||
@ -195,11 +205,6 @@ void VM_Version::initialize() {
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
|
||||
}
|
||||
|
||||
if (UseAdler32Intrinsics) {
|
||||
warning("Adler32Intrinsics not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseAdler32Intrinsics, false);
|
||||
}
|
||||
|
||||
if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
|
||||
FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, true);
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||
__ load_klass(rcvr_klass, Z_ARG1);
|
||||
|
||||
// Set method (in case of interpreted method), and destination address.
|
||||
int entry_offset = in_bytes(InstanceKlass::vtable_start_offset()) +
|
||||
int entry_offset = in_bytes(Klass::vtable_start_offset()) +
|
||||
vtable_index * vtableEntry::size_in_bytes();
|
||||
|
||||
#ifndef PRODUCT
|
||||
@ -96,8 +96,8 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||
// worst case actual size
|
||||
padding_bytes += __ load_const_size() - __ load_const_optimized_rtn_len(vtable_idx, vtable_index*vtableEntry::size_in_bytes(), true);
|
||||
|
||||
assert(Immediate::is_uimm12(in_bytes(InstanceKlass::vtable_length_offset())), "disp to large");
|
||||
__ z_cl(vtable_idx, in_bytes(InstanceKlass::vtable_length_offset()), rcvr_klass);
|
||||
assert(Immediate::is_uimm12(in_bytes(Klass::vtable_length_offset())), "disp to large");
|
||||
__ z_cl(vtable_idx, in_bytes(Klass::vtable_length_offset()), rcvr_klass);
|
||||
__ z_brl(L);
|
||||
__ z_lghi(Z_ARG3, vtable_index); // Debug code, don't optimize.
|
||||
__ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), Z_ARG1, Z_ARG3, false);
|
||||
@ -187,11 +187,11 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
|
||||
__ load_klass(rcvr_klass, Z_ARG1);
|
||||
|
||||
// Load start of itable entries into itable_entry.
|
||||
__ z_llgf(vtable_len, Address(rcvr_klass, InstanceKlass::vtable_length_offset()));
|
||||
__ z_llgf(vtable_len, Address(rcvr_klass, Klass::vtable_length_offset()));
|
||||
__ z_sllg(vtable_len, vtable_len, exact_log2(vtableEntry::size_in_bytes()));
|
||||
|
||||
// Loop over all itable entries until desired interfaceOop(Rinterface) found.
|
||||
const int vtable_base_offset = in_bytes(InstanceKlass::vtable_start_offset());
|
||||
const int vtable_base_offset = in_bytes(Klass::vtable_start_offset());
|
||||
// Count unused bytes.
|
||||
start_pc = __ pc();
|
||||
__ add2reg_with_index(itable_entry_addr, vtable_base_offset + itableOffsetEntry::interface_offset_in_bytes(), rcvr_klass, vtable_len);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -70,9 +70,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
bool check_exception=true
|
||||
);
|
||||
|
||||
virtual void check_and_handle_popframe(Register java_thread);
|
||||
virtual void check_and_handle_earlyret(Register java_thread);
|
||||
|
||||
// base routine for all dispatches
|
||||
void dispatch_base(TosState state, address* table);
|
||||
|
||||
@ -80,6 +77,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
InterpreterMacroAssembler(CodeBuffer* c)
|
||||
: MacroAssembler(c) {}
|
||||
|
||||
virtual void check_and_handle_popframe(Register scratch_reg);
|
||||
virtual void check_and_handle_earlyret(Register scratch_reg);
|
||||
|
||||
void jump_to_entry(address entry);
|
||||
|
||||
virtual void load_earlyret_value(TosState state);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -44,7 +44,7 @@ jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, Hand
|
||||
|
||||
void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) {
|
||||
address pc = _instructions->start() + pc_offset;
|
||||
Handle obj = HotSpotObjectConstantImpl::object(constant);
|
||||
Handle obj(THREAD, HotSpotObjectConstantImpl::object(constant));
|
||||
jobject value = JNIHandles::make_local(obj());
|
||||
if (HotSpotObjectConstantImpl::compressed(constant)) {
|
||||
#ifdef _LP64
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -604,15 +604,15 @@ class MacroAssembler : public Assembler {
|
||||
bool check_exception=true // flag which indicates if exception should be checked
|
||||
);
|
||||
|
||||
public:
|
||||
MacroAssembler(CodeBuffer* code) : Assembler(code) {}
|
||||
|
||||
// This routine should emit JVMTI PopFrame and ForceEarlyReturn handling code.
|
||||
// The implementation is only non-empty for the InterpreterMacroAssembler,
|
||||
// as only the interpreter handles and ForceEarlyReturn PopFrame requests.
|
||||
virtual void check_and_handle_popframe(Register scratch_reg);
|
||||
virtual void check_and_handle_earlyret(Register scratch_reg);
|
||||
|
||||
public:
|
||||
MacroAssembler(CodeBuffer* code) : Assembler(code) {}
|
||||
|
||||
// Support for NULL-checks
|
||||
//
|
||||
// Generates code that causes a NULL OS exception if the content of reg is NULL.
|
||||
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "asm/codeBuffer.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
|
||||
// Generate the self-patching vtable method:
|
||||
//
|
||||
// This method will be called (as any other Klass virtual method) with
|
||||
// the Klass itself as the first argument. Example:
|
||||
//
|
||||
// oop obj;
|
||||
// int size = obj->klass()->oop_size(this);
|
||||
//
|
||||
// for which the virtual method call is Klass::oop_size();
|
||||
//
|
||||
// The dummy method is called with the Klass object as the first
|
||||
// operand, and an object as the second argument.
|
||||
//
|
||||
|
||||
//=====================================================================
|
||||
|
||||
// All of the dummy methods in the vtable are essentially identical,
|
||||
// differing only by an ordinal constant, and they bear no relationship
|
||||
// to the original method which the caller intended. Also, there needs
|
||||
// to be 'vtbl_list_size' instances of the vtable in order to
|
||||
// differentiate between the 'vtable_list_size' original Klass objects.
|
||||
|
||||
#define __ masm->
|
||||
|
||||
void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
|
||||
void** vtable,
|
||||
char** md_top,
|
||||
char* md_end,
|
||||
char** mc_top,
|
||||
char* mc_end) {
|
||||
|
||||
intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
|
||||
*(intptr_t *)(*md_top) = vtable_bytes;
|
||||
*md_top += sizeof(intptr_t);
|
||||
void** dummy_vtable = (void**)*md_top;
|
||||
*vtable = dummy_vtable;
|
||||
*md_top += vtable_bytes;
|
||||
|
||||
// Get ready to generate dummy methods.
|
||||
|
||||
CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
|
||||
MacroAssembler* masm = new MacroAssembler(&cb);
|
||||
|
||||
Label common_code;
|
||||
for (int i = 0; i < vtbl_list_size; ++i) {
|
||||
for (int j = 0; j < num_virtuals; ++j) {
|
||||
dummy_vtable[num_virtuals * i + j] = (void*)masm->pc();
|
||||
__ save(SP, -256, SP);
|
||||
int offset = (i << 8) + j;
|
||||
Register src = G0;
|
||||
if (!Assembler::is_simm13(offset)) {
|
||||
__ sethi(offset, L0);
|
||||
src = L0;
|
||||
offset = offset & ((1 << 10) - 1);
|
||||
}
|
||||
__ brx(Assembler::always, false, Assembler::pt, common_code);
|
||||
|
||||
// Load L0 with a value indicating vtable/offset pair.
|
||||
// -- bits[ 7..0] (8 bits) which virtual method in table?
|
||||
// -- bits[13..8] (6 bits) which virtual method table?
|
||||
__ delayed()->or3(src, offset, L0);
|
||||
}
|
||||
}
|
||||
|
||||
__ bind(common_code);
|
||||
|
||||
// Expecting to be called with the "this" pointer in O0/I0 (where
|
||||
// "this" is a Klass object). In addition, L0 was set (above) to
|
||||
// identify the method and table.
|
||||
|
||||
// Look up the correct vtable pointer.
|
||||
|
||||
__ set((intptr_t)vtbl_list, L2); // L2 = address of new vtable list.
|
||||
__ srl(L0, 8, L3); // Isolate L3 = vtable identifier.
|
||||
__ sll(L3, LogBytesPerWord, L3);
|
||||
__ ld_ptr(L2, L3, L3); // L3 = new (correct) vtable pointer.
|
||||
__ st_ptr(L3, Address(I0, 0)); // Save correct vtable ptr in entry.
|
||||
|
||||
// Restore registers and jump to the correct method;
|
||||
|
||||
__ and3(L0, 255, L4); // Isolate L3 = method offset;.
|
||||
__ sll(L4, LogBytesPerWord, L4);
|
||||
__ ld_ptr(L3, L4, L4); // Get address of correct virtual method
|
||||
__ jmpl(L4, 0, G0); // Jump to correct method.
|
||||
__ delayed()->restore(); // Restore registers.
|
||||
|
||||
__ flush();
|
||||
*mc_top = (char*)__ pc();
|
||||
|
||||
guarantee(*mc_top <= mc_end, "Insufficient space for method wrappers.");
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -71,7 +71,7 @@ void MethodHandles::verify_klass(MacroAssembler* _masm,
|
||||
Register temp_reg, Register temp2_reg,
|
||||
const char* error_message) {
|
||||
InstanceKlass** klass_addr = SystemDictionary::well_known_klass_addr(klass_id);
|
||||
KlassHandle klass = SystemDictionary::well_known_klass(klass_id);
|
||||
Klass* klass = SystemDictionary::well_known_klass(klass_id);
|
||||
bool did_save = false;
|
||||
if (temp_reg == noreg || temp2_reg == noreg) {
|
||||
temp_reg = L1;
|
||||
|
@ -374,6 +374,10 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
|
||||
__ and3(flags, ConstantPoolCacheEntry::parameter_size_mask, parameter_size); // argument size in words
|
||||
__ sll(parameter_size, Interpreter::logStackElementSize, parameter_size); // each argument size in bytes
|
||||
__ add(Lesp, parameter_size, Lesp); // pop arguments
|
||||
|
||||
__ check_and_handle_popframe(Gtemp);
|
||||
__ check_and_handle_earlyret(Gtemp);
|
||||
|
||||
__ dispatch_next(state, step);
|
||||
|
||||
return entry;
|
||||
@ -466,12 +470,6 @@ address TemplateInterpreterGenerator::generate_safept_entry_for(TosState state,
|
||||
}
|
||||
|
||||
|
||||
address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
|
||||
address entry = __ pc();
|
||||
__ dispatch_next(state);
|
||||
return entry;
|
||||
}
|
||||
|
||||
//
|
||||
// Helpers for commoning out cases in the various type of method entries.
|
||||
//
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -21,6 +21,8 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
|
||||
#include "aot/compiledIC_aot.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -48,9 +48,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
int number_of_arguments,
|
||||
bool check_exceptions);
|
||||
|
||||
virtual void check_and_handle_popframe(Register java_thread);
|
||||
virtual void check_and_handle_earlyret(Register java_thread);
|
||||
|
||||
// base routine for all dispatches
|
||||
void dispatch_base(TosState state, address* table, bool verifyoop = true);
|
||||
|
||||
@ -61,6 +58,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
|
||||
void jump_to_entry(address entry);
|
||||
|
||||
virtual void check_and_handle_popframe(Register java_thread);
|
||||
virtual void check_and_handle_earlyret(Register java_thread);
|
||||
|
||||
void load_earlyret_value(TosState state);
|
||||
|
||||
// Interpreter-specific registers
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -65,7 +65,7 @@ jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, Hand
|
||||
|
||||
void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) {
|
||||
address pc = _instructions->start() + pc_offset;
|
||||
Handle obj = HotSpotObjectConstantImpl::object(constant);
|
||||
Handle obj(THREAD, HotSpotObjectConstantImpl::object(constant));
|
||||
jobject value = JNIHandles::make_local(obj());
|
||||
if (HotSpotObjectConstantImpl::compressed(constant)) {
|
||||
#ifdef _LP64
|
||||
|
@ -71,12 +71,6 @@ class MacroAssembler: public Assembler {
|
||||
bool check_exceptions // whether to check for pending exceptions after return
|
||||
);
|
||||
|
||||
// These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code.
|
||||
// The implementation is only non-empty for the InterpreterMacroAssembler,
|
||||
// as only the interpreter handles PopFrame and ForceEarlyReturn requests.
|
||||
virtual void check_and_handle_popframe(Register java_thread);
|
||||
virtual void check_and_handle_earlyret(Register java_thread);
|
||||
|
||||
void call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions = true);
|
||||
|
||||
// helpers for FPU flag access
|
||||
@ -87,6 +81,12 @@ class MacroAssembler: public Assembler {
|
||||
public:
|
||||
MacroAssembler(CodeBuffer* code) : Assembler(code) {}
|
||||
|
||||
// These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code.
|
||||
// The implementation is only non-empty for the InterpreterMacroAssembler,
|
||||
// as only the interpreter handles PopFrame and ForceEarlyReturn requests.
|
||||
virtual void check_and_handle_popframe(Register java_thread);
|
||||
virtual void check_and_handle_earlyret(Register java_thread);
|
||||
|
||||
// Support for NULL-checks
|
||||
//
|
||||
// Generates code that causes a NULL OS exception if the content of reg is NULL.
|
||||
|
@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/codeBuffer.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
|
||||
// Generate the self-patching vtable method:
|
||||
//
|
||||
// This method will be called (as any other Klass virtual method) with
|
||||
// the Klass itself as the first argument. Example:
|
||||
//
|
||||
// oop obj;
|
||||
// int size = obj->klass()->oop_size(this);
|
||||
//
|
||||
// for which the virtual method call is Klass::oop_size();
|
||||
//
|
||||
// The dummy method is called with the Klass object as the first
|
||||
// operand, and an object as the second argument.
|
||||
//
|
||||
|
||||
//=====================================================================
|
||||
|
||||
// All of the dummy methods in the vtable are essentially identical,
|
||||
// differing only by an ordinal constant, and they bear no relationship
|
||||
// to the original method which the caller intended. Also, there needs
|
||||
// to be 'vtbl_list_size' instances of the vtable in order to
|
||||
// differentiate between the 'vtable_list_size' original Klass objects.
|
||||
|
||||
#define __ masm->
|
||||
|
||||
void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
|
||||
void** vtable,
|
||||
char** md_top,
|
||||
char* md_end,
|
||||
char** mc_top,
|
||||
char* mc_end) {
|
||||
|
||||
intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
|
||||
*(intptr_t *)(*md_top) = vtable_bytes;
|
||||
*md_top += sizeof(intptr_t);
|
||||
void** dummy_vtable = (void**)*md_top;
|
||||
*vtable = dummy_vtable;
|
||||
*md_top += vtable_bytes;
|
||||
|
||||
// Get ready to generate dummy methods.
|
||||
|
||||
CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
|
||||
MacroAssembler* masm = new MacroAssembler(&cb);
|
||||
|
||||
Label common_code;
|
||||
for (int i = 0; i < vtbl_list_size; ++i) {
|
||||
for (int j = 0; j < num_virtuals; ++j) {
|
||||
dummy_vtable[num_virtuals * i + j] = (void*)masm->pc();
|
||||
|
||||
// Load rax, with a value indicating vtable/offset pair.
|
||||
// -- bits[ 7..0] (8 bits) which virtual method in table?
|
||||
// -- bits[12..8] (5 bits) which virtual method table?
|
||||
// -- must fit in 13-bit instruction immediate field.
|
||||
__ movl(rax, (i << 8) + j);
|
||||
__ jmp(common_code);
|
||||
}
|
||||
}
|
||||
|
||||
__ bind(common_code);
|
||||
|
||||
#ifdef WIN32
|
||||
// Expecting to be called with "thiscall" conventions -- the arguments
|
||||
// are on the stack, except that the "this" pointer is in rcx.
|
||||
#else
|
||||
// Expecting to be called with Unix conventions -- the arguments
|
||||
// are on the stack, including the "this" pointer.
|
||||
#endif
|
||||
|
||||
// In addition, rax was set (above) to the offset of the method in the
|
||||
// table.
|
||||
|
||||
#ifdef WIN32
|
||||
__ push(rcx); // save "this"
|
||||
#endif
|
||||
__ mov(rcx, rax);
|
||||
__ shrptr(rcx, 8); // isolate vtable identifier.
|
||||
__ shlptr(rcx, LogBytesPerWord);
|
||||
Address index(noreg, rcx, Address::times_1);
|
||||
ExternalAddress vtbl((address)vtbl_list);
|
||||
__ movptr(rdx, ArrayAddress(vtbl, index)); // get correct vtable address.
|
||||
#ifdef WIN32
|
||||
__ pop(rcx); // restore "this"
|
||||
#else
|
||||
__ movptr(rcx, Address(rsp, BytesPerWord)); // fetch "this"
|
||||
#endif
|
||||
__ movptr(Address(rcx, 0), rdx); // update vtable pointer.
|
||||
|
||||
__ andptr(rax, 0x00ff); // isolate vtable method index
|
||||
__ shlptr(rax, LogBytesPerWord);
|
||||
__ addptr(rax, rdx); // address of real method pointer.
|
||||
__ jmp(Address(rax, 0)); // get real method pointer.
|
||||
|
||||
__ flush();
|
||||
|
||||
*mc_top = (char*)__ pc();
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/codeBuffer.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
|
||||
// Generate the self-patching vtable method:
|
||||
//
|
||||
// This method will be called (as any other Klass virtual method) with
|
||||
// the Klass itself as the first argument. Example:
|
||||
//
|
||||
// oop obj;
|
||||
// int size = obj->klass()->oop_size(this);
|
||||
//
|
||||
// for which the virtual method call is Klass::oop_size();
|
||||
//
|
||||
// The dummy method is called with the Klass object as the first
|
||||
// operand, and an object as the second argument.
|
||||
//
|
||||
|
||||
//=====================================================================
|
||||
|
||||
// All of the dummy methods in the vtable are essentially identical,
|
||||
// differing only by an ordinal constant, and they bear no relationship
|
||||
// to the original method which the caller intended. Also, there needs
|
||||
// to be 'vtbl_list_size' instances of the vtable in order to
|
||||
// differentiate between the 'vtable_list_size' original Klass objects.
|
||||
|
||||
#define __ masm->
|
||||
|
||||
void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
|
||||
void** vtable,
|
||||
char** md_top,
|
||||
char* md_end,
|
||||
char** mc_top,
|
||||
char* mc_end) {
|
||||
|
||||
intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
|
||||
*(intptr_t *)(*md_top) = vtable_bytes;
|
||||
*md_top += sizeof(intptr_t);
|
||||
void** dummy_vtable = (void**)*md_top;
|
||||
*vtable = dummy_vtable;
|
||||
*md_top += vtable_bytes;
|
||||
|
||||
// Get ready to generate dummy methods.
|
||||
|
||||
CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
|
||||
MacroAssembler* masm = new MacroAssembler(&cb);
|
||||
|
||||
Label common_code;
|
||||
for (int i = 0; i < vtbl_list_size; ++i) {
|
||||
for (int j = 0; j < num_virtuals; ++j) {
|
||||
dummy_vtable[num_virtuals * i + j] = (void*)masm->pc();
|
||||
|
||||
// Load eax with a value indicating vtable/offset pair.
|
||||
// -- bits[ 7..0] (8 bits) which virtual method in table?
|
||||
// -- bits[12..8] (5 bits) which virtual method table?
|
||||
// -- must fit in 13-bit instruction immediate field.
|
||||
__ movl(rax, (i << 8) + j);
|
||||
__ jmp(common_code);
|
||||
}
|
||||
}
|
||||
|
||||
__ bind(common_code);
|
||||
|
||||
// Expecting to be called with "thiscall" convections -- the arguments
|
||||
// are on the stack and the "this" pointer is in c_rarg0. In addition, rax
|
||||
// was set (above) to the offset of the method in the table.
|
||||
|
||||
__ push(c_rarg1); // save & free register
|
||||
__ push(c_rarg0); // save "this"
|
||||
__ mov(c_rarg0, rax);
|
||||
__ shrptr(c_rarg0, 8); // isolate vtable identifier.
|
||||
__ shlptr(c_rarg0, LogBytesPerWord);
|
||||
__ lea(c_rarg1, ExternalAddress((address)vtbl_list)); // ptr to correct vtable list.
|
||||
__ addptr(c_rarg1, c_rarg0); // ptr to list entry.
|
||||
__ movptr(c_rarg1, Address(c_rarg1, 0)); // get correct vtable address.
|
||||
__ pop(c_rarg0); // restore "this"
|
||||
__ movptr(Address(c_rarg0, 0), c_rarg1); // update vtable pointer.
|
||||
|
||||
__ andptr(rax, 0x00ff); // isolate vtable method index
|
||||
__ shlptr(rax, LogBytesPerWord);
|
||||
__ addptr(rax, c_rarg1); // address of real method pointer.
|
||||
__ pop(c_rarg1); // restore register.
|
||||
__ movptr(rax, Address(rax, 0)); // get real method pointer.
|
||||
__ jmp(rax); // jump to the real method.
|
||||
|
||||
__ flush();
|
||||
|
||||
*mc_top = (char*)__ pc();
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -65,7 +65,7 @@ void MethodHandles::verify_klass(MacroAssembler* _masm,
|
||||
Register obj, SystemDictionary::WKID klass_id,
|
||||
const char* error_message) {
|
||||
InstanceKlass** klass_addr = SystemDictionary::well_known_klass_addr(klass_id);
|
||||
KlassHandle klass = SystemDictionary::well_known_klass(klass_id);
|
||||
Klass* klass = SystemDictionary::well_known_klass(klass_id);
|
||||
Register temp = rdi;
|
||||
Register temp2 = noreg;
|
||||
LP64_ONLY(temp2 = rscratch1); // used by MacroAssembler::cmpptr
|
||||
|
@ -171,16 +171,6 @@ address TemplateInterpreterGenerator::generate_exception_handler_common(
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
|
||||
address entry = __ pc();
|
||||
// NULL last_sp until next java call
|
||||
__ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD);
|
||||
__ dispatch_next(state);
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
|
||||
address entry = __ pc();
|
||||
|
||||
@ -230,6 +220,17 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
|
||||
__ movl(flags, Address(cache, index, Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()));
|
||||
__ andl(flags, ConstantPoolCacheEntry::parameter_size_mask);
|
||||
__ lea(rsp, Address(rsp, flags, Interpreter::stackElementScale()));
|
||||
|
||||
const Register java_thread = NOT_LP64(rcx) LP64_ONLY(r15_thread);
|
||||
if (JvmtiExport::can_pop_frame()) {
|
||||
NOT_LP64(__ get_thread(java_thread));
|
||||
__ check_and_handle_popframe(java_thread);
|
||||
}
|
||||
if (JvmtiExport::can_force_early_return()) {
|
||||
NOT_LP64(__ get_thread(java_thread));
|
||||
__ check_and_handle_earlyret(java_thread);
|
||||
}
|
||||
|
||||
__ dispatch_next(state, step);
|
||||
|
||||
return entry;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -36,16 +36,19 @@ import java.util.Map;
|
||||
import jdk.tools.jaotc.binformat.Symbol.Binding;
|
||||
import jdk.tools.jaotc.binformat.Symbol.Kind;
|
||||
import jdk.tools.jaotc.binformat.elf.JELFRelocObject;
|
||||
import jdk.tools.jaotc.binformat.macho.JMachORelocObject;
|
||||
import jdk.tools.jaotc.binformat.pecoff.JPECoffRelocObject;
|
||||
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
|
||||
/**
|
||||
* A format-agnostic container class that holds various components of a binary.
|
||||
*
|
||||
* <p>
|
||||
* This class holds information necessary to create platform-specific binary containers such as
|
||||
* ELFContainer for Linux and Solaris operating systems or yet-to be created MachOContainer for Mac
|
||||
* OS or PEContainer for MS Windows operating systems.
|
||||
* ELFContainer for Linux and Solaris operating systems or MachOContainer for Mac OS or PEContainer
|
||||
* for MS Windows operating systems.
|
||||
*
|
||||
* <p>
|
||||
* Method APIs provided by this class are used to construct and populate platform-independent
|
||||
@ -56,6 +59,7 @@ import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
|
||||
* Methods to record and access code section contents, symbols and relocations are provided.
|
||||
*/
|
||||
public class BinaryContainer implements SymbolTable {
|
||||
private final OptionValues graalOptions;
|
||||
|
||||
private final int codeSegmentSize;
|
||||
|
||||
@ -257,36 +261,40 @@ public class BinaryContainer implements SymbolTable {
|
||||
* Allocates a {@code BinaryContainer} object whose content will be generated in a file with the
|
||||
* prefix {@code prefix}. It also initializes internal code container, symbol table and
|
||||
* relocation tables.
|
||||
*
|
||||
* @param graalOptions
|
||||
*/
|
||||
public BinaryContainer(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig, String jvmVersion) {
|
||||
public BinaryContainer(OptionValues graalOptions, GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig, String jvmVersion) {
|
||||
this.graalOptions = graalOptions;
|
||||
|
||||
this.codeSegmentSize = graalHotSpotVMConfig.codeSegmentSize;
|
||||
this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment;
|
||||
|
||||
// read only, code
|
||||
codeContainer = new CodeContainer(".text", this);
|
||||
extLinkageContainer = new CodeContainer(".hotspot.linkage.plt", this);
|
||||
extLinkageContainer = new CodeContainer(".hs.plt.linkage", this);
|
||||
|
||||
// read only, info
|
||||
configContainer = new ReadOnlyDataContainer(".config", this);
|
||||
metaspaceNamesContainer = new ReadOnlyDataContainer(".metaspace.names", this);
|
||||
metaspaceNamesContainer = new ReadOnlyDataContainer(".meta.names", this);
|
||||
methodsOffsetsContainer = new ReadOnlyDataContainer(".methods.offsets", this);
|
||||
klassesOffsetsContainer = new ReadOnlyDataContainer(".klasses.offsets", this);
|
||||
klassesDependenciesContainer = new ReadOnlyDataContainer(".klasses.dependencies", this);
|
||||
klassesOffsetsContainer = new ReadOnlyDataContainer(".kls.offsets", this);
|
||||
klassesDependenciesContainer = new ReadOnlyDataContainer(".kls.dependencies", this);
|
||||
|
||||
headerContainer = new HeaderContainer(jvmVersion, new ReadOnlyDataContainer(".header", this));
|
||||
stubsOffsetsContainer = new ReadOnlyDataContainer(".stubs.offsets", this);
|
||||
codeSegmentsContainer = new ReadOnlyDataContainer(".code.segments", this);
|
||||
constantDataContainer = new ReadOnlyDataContainer(".method.constdata", this);
|
||||
constantDataContainer = new ReadOnlyDataContainer(".meth.constdata", this);
|
||||
|
||||
// needs relocation patching at load time by the loader
|
||||
methodMetadataContainer = new ReadOnlyDataContainer(".method.metadata", this);
|
||||
methodMetadataContainer = new ReadOnlyDataContainer(".meth.metadata", this);
|
||||
|
||||
// writable sections
|
||||
metaspaceGotContainer = new ByteContainer(".metaspace.got", this);
|
||||
metaspaceGotContainer = new ByteContainer(".meta.got", this);
|
||||
metadataGotContainer = new ByteContainer(".metadata.got", this);
|
||||
methodStateContainer = new ByteContainer(".method.state", this);
|
||||
methodStateContainer = new ByteContainer(".meth.state", this);
|
||||
oopGotContainer = new ByteContainer(".oop.got", this);
|
||||
extLinkageGOTContainer = new ByteContainer(".hotspot.linkage.got", this);
|
||||
extLinkageGOTContainer = new ByteContainer(".hs.got.linkage", this);
|
||||
|
||||
addGlobalSymbols();
|
||||
|
||||
@ -303,17 +311,17 @@ public class BinaryContainer implements SymbolTable {
|
||||
graalHotSpotVMConfig.useCMSGC,
|
||||
graalHotSpotVMConfig.useTLAB,
|
||||
graalHotSpotVMConfig.useBiasedLocking,
|
||||
TieredAOT.getValue(),
|
||||
TieredAOT.getValue(graalOptions),
|
||||
graalHotSpotVMConfig.enableContended,
|
||||
graalHotSpotVMConfig.restrictContended,
|
||||
graphBuilderConfig.omitAssertions()
|
||||
};
|
||||
|
||||
int[] intFlags = { graalHotSpotVMConfig.getOopEncoding().shift,
|
||||
graalHotSpotVMConfig.getKlassEncoding().shift,
|
||||
int[] intFlags = { graalHotSpotVMConfig.getOopEncoding().getShift(),
|
||||
graalHotSpotVMConfig.getKlassEncoding().getShift(),
|
||||
graalHotSpotVMConfig.contendedPaddingWidth,
|
||||
graalHotSpotVMConfig.fieldsAllocationStyle,
|
||||
1 << graalHotSpotVMConfig.getOopEncoding().alignment,
|
||||
1 << graalHotSpotVMConfig.logMinObjAlignment(),
|
||||
graalHotSpotVMConfig.codeSegmentSize,
|
||||
};
|
||||
// @formatter:on
|
||||
@ -497,11 +505,20 @@ public class BinaryContainer implements SymbolTable {
|
||||
switch (osName) {
|
||||
case "Linux":
|
||||
case "SunOS":
|
||||
JELFRelocObject elfso = new JELFRelocObject(this, outputFileName, aotVersion);
|
||||
elfso.createELFRelocObject(relocationTable, symbolTable.values());
|
||||
JELFRelocObject elfobj = new JELFRelocObject(this, outputFileName, aotVersion);
|
||||
elfobj.createELFRelocObject(relocationTable, symbolTable.values());
|
||||
break;
|
||||
case "Mac OS X":
|
||||
JMachORelocObject machobj = new JMachORelocObject(this, outputFileName);
|
||||
machobj.createMachORelocObject(relocationTable, symbolTable.values());
|
||||
break;
|
||||
default:
|
||||
throw new InternalError("Unsupported platform: " + osName);
|
||||
if (osName.startsWith("Windows")) {
|
||||
JPECoffRelocObject pecoffobj = new JPECoffRelocObject(this, outputFileName, aotVersion);
|
||||
pecoffobj.createPECoffRelocObject(relocationTable, symbolTable.values());
|
||||
break;
|
||||
} else
|
||||
throw new InternalError("Unsupported platform: " + osName);
|
||||
}
|
||||
}
|
||||
|
||||
@ -742,11 +759,11 @@ public class BinaryContainer implements SymbolTable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add constant data as follows. - Adding the data to the method.constdata section
|
||||
* Add constant data as follows. - Adding the data to the meth.constdata section
|
||||
*
|
||||
* @param data
|
||||
* @param alignment
|
||||
* @return the offset in the method.constdata of the data
|
||||
* @return the offset in the meth.constdata of the data
|
||||
*/
|
||||
public int addConstantData(byte[] data, int alignment) {
|
||||
// Get the current length of the metaspaceNameContainer
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,7 +25,7 @@ package jdk.tools.jaotc.binformat;
|
||||
|
||||
import jdk.tools.jaotc.binformat.Symbol.Binding;
|
||||
import jdk.tools.jaotc.binformat.Symbol.Kind;
|
||||
import jdk.tools.jaotc.jnilibelf.ELFContainer;
|
||||
import jdk.tools.jaotc.binformat.Container;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -41,7 +41,7 @@ import java.util.Arrays;
|
||||
* The method {@code putIntAt} updates the content of {@code contentBytes}. Changes are not
|
||||
* reflected in {@code contentStream}.
|
||||
*/
|
||||
public class ByteContainer implements ELFContainer {
|
||||
public class ByteContainer implements Container {
|
||||
/**
|
||||
* {@code ByteBuffer} representation of {@code BinaryContainer}.
|
||||
*/
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -21,9 +21,9 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.jnilibelf;
|
||||
package jdk.tools.jaotc.binformat;
|
||||
|
||||
public interface ELFContainer {
|
||||
public interface Container {
|
||||
|
||||
String getContainerName();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -21,27 +21,31 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.jnilibelf.sunos;
|
||||
package jdk.tools.jaotc.binformat;
|
||||
|
||||
/**
|
||||
* Represent Elf_Cmd enums defined in libelf.h on SunOS as they slightly different from libelf.h on
|
||||
* Linux.
|
||||
* This class represents ia native OS specific Symbol
|
||||
*/
|
||||
public enum Elf_Cmd {
|
||||
/** Must be first, 0. */
|
||||
ELF_C_NULL,
|
||||
public abstract class NativeSymbol {
|
||||
|
||||
ELF_C_READ,
|
||||
ELF_C_WRITE,
|
||||
ELF_C_CLR,
|
||||
ELF_C_SET,
|
||||
ELF_C_FDDONE,
|
||||
ELF_C_FDREAD,
|
||||
ELF_C_RDWR,
|
||||
ELF_C_WRIMAGE,
|
||||
ELF_C_IMAGE,
|
||||
/** String table index. */
|
||||
private int index;
|
||||
|
||||
/** Must be last. */
|
||||
ELF_C_NUM
|
||||
public NativeSymbol(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the index
|
||||
*/
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @index
|
||||
*/
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,7 +25,7 @@ package jdk.tools.jaotc.binformat;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.tools.jaotc.jnilibelf.ELFSymbol;
|
||||
import jdk.tools.jaotc.binformat.NativeSymbol;
|
||||
|
||||
public class Symbol {
|
||||
|
||||
@ -51,7 +51,7 @@ public class Symbol {
|
||||
private final Kind kind;
|
||||
|
||||
private ByteContainer section;
|
||||
private ELFSymbol elfSymbol;
|
||||
private NativeSymbol nativeSymbol;
|
||||
|
||||
/**
|
||||
* Create symbol info.
|
||||
@ -77,12 +77,12 @@ public class Symbol {
|
||||
return name;
|
||||
}
|
||||
|
||||
public ELFSymbol getElfSymbol() {
|
||||
return elfSymbol;
|
||||
public NativeSymbol getNativeSymbol() {
|
||||
return nativeSymbol;
|
||||
}
|
||||
|
||||
public void setElfSymbol(ELFSymbol elfSymbol) {
|
||||
this.elfSymbol = elfSymbol;
|
||||
public void setNativeSymbol(NativeSymbol nativeSym) {
|
||||
this.nativeSymbol = nativeSym;
|
||||
}
|
||||
|
||||
public Binding getBinding() {
|
||||
|
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.elf;
|
||||
|
||||
/**
|
||||
*
|
||||
* Support for the creation of Elf Object files.
|
||||
* Current support is limited to 64 bit x86_64.
|
||||
*
|
||||
*/
|
||||
|
||||
public class Elf {
|
||||
|
||||
/**
|
||||
* Elf64_Ehdr structure defines
|
||||
*/
|
||||
public enum Elf64_Ehdr {
|
||||
e_ident( 0,16),
|
||||
e_type(16, 2),
|
||||
e_machine(18, 2),
|
||||
e_version(20, 4),
|
||||
e_entry(24, 8),
|
||||
e_phoff(32, 8),
|
||||
e_shoff(40, 8),
|
||||
e_flags(48, 4),
|
||||
e_ehsize(52, 2),
|
||||
e_phentsize(54, 2),
|
||||
e_phnum(56, 2),
|
||||
e_shentsize(58, 2),
|
||||
e_shnum(60, 2),
|
||||
e_shstrndx(62, 2);
|
||||
|
||||
public final int off;
|
||||
public final int sz;
|
||||
|
||||
Elf64_Ehdr(int offset, int size) {
|
||||
this.off = offset;
|
||||
this.sz = size;
|
||||
}
|
||||
|
||||
public static int totalsize = 64;
|
||||
|
||||
/**
|
||||
* Elf64_Ehdr defines
|
||||
*/
|
||||
|
||||
/**
|
||||
* e_ident
|
||||
*/
|
||||
public static final int EI_MAG0 = 0;
|
||||
public static final byte ELFMAG0 = 0x7f;
|
||||
public static final int EI_MAG1 = 1;
|
||||
public static final byte ELFMAG1 = 0x45;
|
||||
public static final int EI_MAG2 = 2;
|
||||
public static final byte ELFMAG2 = 0x4c;
|
||||
public static final int EI_MAG3 = 3;
|
||||
public static final byte ELFMAG3 = 0x46;
|
||||
|
||||
public static final int EI_CLASS = 4;
|
||||
public static final byte ELFCLASS64 = 0x2;
|
||||
|
||||
public static final int EI_DATA = 5;
|
||||
public static final byte ELFDATA2LSB = 0x1;
|
||||
|
||||
public static final int EI_VERSION = 6;
|
||||
public static final byte EV_CURRENT = 0x1;
|
||||
|
||||
public static final int EI_OSABI = 7;
|
||||
public static final byte ELFOSABI_NONE = 0x0;
|
||||
|
||||
/**
|
||||
* e_type
|
||||
*/
|
||||
public static final char ET_REL = 0x1;
|
||||
|
||||
/**
|
||||
* e_machine
|
||||
*/
|
||||
public static final char EM_NONE = 0;
|
||||
public static final char EM_X86_64 = 62;
|
||||
public static final char EM_AARCH64 = 183;
|
||||
|
||||
/**
|
||||
* e_version
|
||||
*/
|
||||
// public static final int EV_CURRENT = 1;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Elf64_Shdr structure defines
|
||||
*/
|
||||
public enum Elf64_Shdr {
|
||||
sh_name( 0, 4),
|
||||
sh_type( 4, 4),
|
||||
sh_flags( 8, 8),
|
||||
sh_addr(16, 8),
|
||||
sh_offset(24, 8),
|
||||
sh_size(32, 8),
|
||||
sh_link(40, 4),
|
||||
sh_info(44, 4),
|
||||
sh_addralign(48, 8),
|
||||
sh_entsize(56, 8);
|
||||
|
||||
public final int off;
|
||||
public final int sz;
|
||||
|
||||
Elf64_Shdr(int offset, int size) {
|
||||
this.off = offset;
|
||||
this.sz = size;
|
||||
}
|
||||
|
||||
public static int totalsize = 64;
|
||||
|
||||
/**
|
||||
* Elf64_Shdr defines
|
||||
*/
|
||||
|
||||
/**
|
||||
* sh_type
|
||||
*/
|
||||
public static final int SHT_PROGBITS = 0x1;
|
||||
public static final int SHT_SYMTAB = 0x2;
|
||||
public static final int SHT_STRTAB = 0x3;
|
||||
public static final int SHT_RELA = 0x4;
|
||||
public static final int SHT_NOBITS = 0x8;
|
||||
public static final int SHT_REL = 0x9;
|
||||
|
||||
public static final byte SHN_UNDEF = 0x0;
|
||||
|
||||
/**
|
||||
* sh_flag
|
||||
*/
|
||||
public static final int SHF_WRITE = 0x1;
|
||||
public static final int SHF_ALLOC = 0x2;
|
||||
public static final int SHF_EXECINSTR = 0x4;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Symbol table entry definitions
|
||||
*
|
||||
* Elf64_Sym structure defines
|
||||
*/
|
||||
public enum Elf64_Sym {
|
||||
st_name( 0, 4),
|
||||
st_info( 4, 1),
|
||||
st_other( 5, 1),
|
||||
st_shndx( 6, 2),
|
||||
st_value( 8, 8),
|
||||
st_size(16, 8);
|
||||
|
||||
public final int off;
|
||||
public final int sz;
|
||||
|
||||
Elf64_Sym(int offset, int size) {
|
||||
this.off = offset;
|
||||
this.sz = size;
|
||||
}
|
||||
|
||||
public static int totalsize = 24;
|
||||
|
||||
/* ST_BIND is in bits 4-7 of st_info. ST_TYPE is in low 4 bits */
|
||||
public static final byte STB_LOCAL = 0x0;
|
||||
public static final byte STB_GLOBAL = 0x1;
|
||||
|
||||
public static final byte STT_NOTYPE = 0x0;
|
||||
public static final byte STT_OBJECT = 0x1;
|
||||
public static final byte STT_FUNC = 0x2;
|
||||
|
||||
public static byte ELF64_ST_INFO(byte bind, byte type) {
|
||||
return (byte)(((bind) << 4) + ((type) & 0xf));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Elf64_Rel structure defines
|
||||
*/
|
||||
public enum Elf64_Rel {
|
||||
r_offset( 0, 8),
|
||||
r_info( 8, 8);
|
||||
|
||||
public final int off;
|
||||
public final int sz;
|
||||
|
||||
Elf64_Rel(int offset, int size) {
|
||||
this.off = offset;
|
||||
this.sz = size;
|
||||
}
|
||||
|
||||
public static int totalsize = 16;
|
||||
|
||||
/**
|
||||
* Relocation types
|
||||
*/
|
||||
public static final int R_X86_64_NONE = 0x0;
|
||||
public static final int R_X86_64_64 = 0x1;
|
||||
public static final int R_X86_64_PC32 = 0x2;
|
||||
public static final int R_X86_64_PLT32 = 0x4;
|
||||
public static final int R_X86_64_GOTPCREL = 0x9;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Elf64_Rela structure defines
|
||||
*/
|
||||
public enum Elf64_Rela {
|
||||
r_offset( 0, 8),
|
||||
r_info( 8, 8),
|
||||
r_addend(16, 8);
|
||||
|
||||
public final int off;
|
||||
public final int sz;
|
||||
|
||||
Elf64_Rela(int offset, int size) {
|
||||
this.off = offset;
|
||||
this.sz = size;
|
||||
}
|
||||
|
||||
public static int totalsize = 24;
|
||||
|
||||
public static final int R_X86_64_NONE = 0x0;
|
||||
public static final int R_X86_64_64 = 0x1;
|
||||
public static final int R_X86_64_PC32 = 0x2;
|
||||
public static final int R_X86_64_PLT32 = 0x4;
|
||||
public static final int R_X86_64_GOTPCREL = 0x9;
|
||||
|
||||
public static long ELF64_R_INFO(int symidx, int type) {
|
||||
return (((long)symidx << 32) + ((long)type));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -20,20 +20,24 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.salver.serialize;
|
||||
|
||||
import java.io.Flushable;
|
||||
import java.io.IOException;
|
||||
package jdk.tools.jaotc.binformat.elf;
|
||||
|
||||
import org.graalvm.compiler.salver.writer.DumpWriter;
|
||||
|
||||
public interface Serializer extends Flushable {
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
|
||||
import jdk.tools.jaotc.binformat.elf.ElfTargetInfo;
|
||||
|
||||
DumpWriter getWriter();
|
||||
public class ElfByteBuffer {
|
||||
|
||||
void setWriter(DumpWriter writer);
|
||||
public static ByteBuffer allocate(int size) {
|
||||
ByteBuffer buf = ByteBuffer.allocate(size);
|
||||
if (ElfTargetInfo.getElfEndian() == Elf64_Ehdr.ELFDATA2LSB)
|
||||
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||
else
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
return (buf);
|
||||
}
|
||||
|
||||
Serializer serialize(Object obj) throws IOException;
|
||||
|
||||
void reset() throws IOException;
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.elf;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
public class ElfContainer {
|
||||
|
||||
File outputFile;
|
||||
FileOutputStream outputStream;
|
||||
long fileOffset;
|
||||
|
||||
public ElfContainer(String fileName, String aotVersion) {
|
||||
String baseName;
|
||||
|
||||
outputFile = new File(fileName);
|
||||
if (outputFile.exists()) {
|
||||
outputFile.delete();
|
||||
}
|
||||
|
||||
try {
|
||||
outputStream = new FileOutputStream(outputFile);
|
||||
} catch (Exception e) {
|
||||
System.out.println("ElfContainer: Can't create file " + fileName);
|
||||
}
|
||||
fileOffset = 0;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
outputStream.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println("ElfContainer: close failed");
|
||||
}
|
||||
}
|
||||
|
||||
public void writeBytes(byte [] bytes) {
|
||||
if (bytes == null) return;
|
||||
try {
|
||||
outputStream.write(bytes);
|
||||
} catch (Exception e) {
|
||||
System.out.println("ElfContainer: writeBytes failed");
|
||||
}
|
||||
fileOffset += bytes.length;
|
||||
}
|
||||
|
||||
// Write bytes to output file with up front alignment padding
|
||||
public void writeBytes(byte [] bytes, int alignment) {
|
||||
if (bytes == null) return;
|
||||
try {
|
||||
// Pad to alignment
|
||||
while ((fileOffset & (long)(alignment-1)) != 0) {
|
||||
outputStream.write(0);
|
||||
fileOffset++;
|
||||
}
|
||||
outputStream.write(bytes);
|
||||
} catch (Exception e) {
|
||||
System.out.println("ElfContainer: writeBytes failed");
|
||||
}
|
||||
fileOffset += bytes.length;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.elf;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.tools.jaotc.binformat.elf.Elf;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Shdr;
|
||||
import jdk.tools.jaotc.binformat.elf.ElfTargetInfo;
|
||||
import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
|
||||
|
||||
public class ElfHeader {
|
||||
ByteBuffer header;
|
||||
|
||||
public ElfHeader() {
|
||||
header = ElfByteBuffer.allocate(Elf64_Ehdr.totalsize);
|
||||
|
||||
header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_MAG0, Elf64_Ehdr.ELFMAG0);
|
||||
header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_MAG1, Elf64_Ehdr.ELFMAG1);
|
||||
header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_MAG2, Elf64_Ehdr.ELFMAG2);
|
||||
header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_MAG3, Elf64_Ehdr.ELFMAG3);
|
||||
header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_CLASS, Elf64_Ehdr.ELFCLASS64);
|
||||
header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_DATA, Elf64_Ehdr.ELFDATA2LSB);
|
||||
header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_VERSION, Elf64_Ehdr.EV_CURRENT);
|
||||
header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_OSABI, Elf64_Ehdr.ELFOSABI_NONE);
|
||||
|
||||
header.putChar(Elf64_Ehdr.e_type.off, Elf64_Ehdr.ET_REL);
|
||||
header.putChar(Elf64_Ehdr.e_machine.off, ElfTargetInfo.getElfArch());
|
||||
header.putInt(Elf64_Ehdr.e_version.off, Elf64_Ehdr.EV_CURRENT);
|
||||
header.putChar(Elf64_Ehdr.e_ehsize.off, (char)Elf64_Ehdr.totalsize);
|
||||
header.putChar(Elf64_Ehdr.e_shentsize.off, (char)Elf64_Shdr.totalsize);
|
||||
|
||||
}
|
||||
|
||||
// Update header with file offset of first section
|
||||
public void setSectionOff(int offset) {
|
||||
header.putLong(Elf64_Ehdr.e_shoff.off, offset);
|
||||
}
|
||||
|
||||
// Update header with the number of total sections
|
||||
public void setSectionNum(int count) {
|
||||
header.putChar(Elf64_Ehdr.e_shnum.off, (char)count);
|
||||
}
|
||||
|
||||
// Update header with the section index containing the
|
||||
// string table for section names
|
||||
public void setSectionStrNdx(int index) {
|
||||
header.putChar(Elf64_Ehdr.e_shstrndx.off, (char)index);
|
||||
}
|
||||
|
||||
public byte[] getArray() {
|
||||
return header.array();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -20,32 +20,32 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.salver.writer;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.Flushable;
|
||||
import java.io.IOException;
|
||||
package jdk.tools.jaotc.binformat.elf;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public interface DumpWriter extends Closeable, Flushable, AutoCloseable {
|
||||
import jdk.tools.jaotc.binformat.elf.Elf;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
|
||||
import jdk.tools.jaotc.binformat.elf.ElfTargetInfo;
|
||||
import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
|
||||
|
||||
DumpWriter write(byte b) throws IOException;
|
||||
public class ElfRelocEntry {
|
||||
ByteBuffer entry;
|
||||
|
||||
DumpWriter write(byte[] arr) throws IOException;
|
||||
public ElfRelocEntry(int offset, int symno, int type, int addend) {
|
||||
|
||||
DumpWriter write(ByteBuffer buf) throws IOException;
|
||||
entry = ElfByteBuffer.allocate(Elf64_Rela.totalsize);
|
||||
|
||||
DumpWriter write(CharSequence csq) throws IOException;
|
||||
entry.putLong(Elf64_Rela.r_offset.off, offset);
|
||||
entry.putLong(Elf64_Rela.r_info.off, Elf64_Rela.ELF64_R_INFO(symno,type));
|
||||
entry.putLong(Elf64_Rela.r_addend.off, addend);
|
||||
}
|
||||
|
||||
DumpWriter writeChar(char v) throws IOException;
|
||||
|
||||
DumpWriter writeShort(short v) throws IOException;
|
||||
|
||||
DumpWriter writeInt(int v) throws IOException;
|
||||
|
||||
DumpWriter writeLong(long v) throws IOException;
|
||||
|
||||
DumpWriter writeFloat(float v) throws IOException;
|
||||
|
||||
DumpWriter writeDouble(double v) throws IOException;
|
||||
public byte[] getArray() {
|
||||
return entry.array();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.elf;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.tools.jaotc.binformat.elf.ElfRelocEntry;
|
||||
import jdk.tools.jaotc.binformat.elf.ElfTargetInfo;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
|
||||
import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
|
||||
|
||||
public class ElfRelocTable {
|
||||
ArrayList<ArrayList<ElfRelocEntry>> relocEntries;
|
||||
|
||||
public ElfRelocTable(int numsects) {
|
||||
relocEntries = new ArrayList<ArrayList<ElfRelocEntry>>(numsects);
|
||||
for (int i = 0; i < numsects; i++)
|
||||
relocEntries.add(new ArrayList<ElfRelocEntry>());
|
||||
}
|
||||
|
||||
public void createRelocationEntry(int sectindex,
|
||||
int offset,
|
||||
int symno,
|
||||
int type,
|
||||
int addend) {
|
||||
|
||||
ElfRelocEntry entry = new ElfRelocEntry(offset,
|
||||
symno,
|
||||
type,
|
||||
addend);
|
||||
relocEntries.get(sectindex).add(entry);
|
||||
}
|
||||
|
||||
public int getNumRelocs(int section_index) {
|
||||
return relocEntries.get(section_index).size();
|
||||
}
|
||||
|
||||
// Return the relocation entries for a single section
|
||||
// or null if no entries added to section
|
||||
public byte [] getRelocData(int section_index) {
|
||||
ArrayList<ElfRelocEntry> entryList = relocEntries.get(section_index);
|
||||
|
||||
if (entryList.size() == 0)
|
||||
return null;
|
||||
|
||||
ByteBuffer relocData = ElfByteBuffer.allocate(entryList.size() * Elf64_Rela.totalsize);
|
||||
|
||||
// Copy each entry to a single ByteBuffer
|
||||
for (int i = 0; i < entryList.size(); i++) {
|
||||
ElfRelocEntry entry = entryList.get(i);
|
||||
relocData.put(entry.getArray());
|
||||
}
|
||||
|
||||
return (relocData.array());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.elf;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.tools.jaotc.binformat.elf.Elf;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Shdr;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rel;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym;
|
||||
import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
|
||||
|
||||
public class ElfSection {
|
||||
String name;
|
||||
ByteBuffer section;
|
||||
byte [] data;
|
||||
boolean hasrelocations;
|
||||
int sectionIndex;
|
||||
|
||||
/**
|
||||
* String holding section name strings
|
||||
*/
|
||||
private static StringBuilder sectNameTab = new StringBuilder();
|
||||
|
||||
/**
|
||||
* Keeps track of bytes in section string table since strTabContent.length()
|
||||
* is number of chars, not bytes.
|
||||
*/
|
||||
private static int shStrTabNrOfBytes = 0;
|
||||
|
||||
public ElfSection(String sectName, byte [] sectData, int sectFlags,
|
||||
int sectType, boolean hasRelocations, int sectIndex) {
|
||||
|
||||
long align;
|
||||
|
||||
section = ElfByteBuffer.allocate(Elf64_Shdr.totalsize);
|
||||
|
||||
// Return all 0's for NULL section
|
||||
if (sectIndex == 0) {
|
||||
sectNameTab.append('\0');
|
||||
shStrTabNrOfBytes += 1;
|
||||
data = null;
|
||||
hasrelocations = false;
|
||||
sectionIndex = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
section.putInt(Elf64_Shdr.sh_name.off, shStrTabNrOfBytes);
|
||||
sectNameTab.append(sectName).append('\0');
|
||||
shStrTabNrOfBytes += (sectName.getBytes().length + 1);
|
||||
name = sectName;
|
||||
|
||||
section.putInt(Elf64_Shdr.sh_type.off, sectType);
|
||||
section.putLong(Elf64_Shdr.sh_flags.off, sectFlags);
|
||||
section.putLong(Elf64_Shdr.sh_addr.off, 0);
|
||||
section.putLong(Elf64_Shdr.sh_offset.off, 0);
|
||||
|
||||
if (sectName.equals(".shstrtab")) {
|
||||
section.putLong(Elf64_Shdr.sh_size.off, shStrTabNrOfBytes);
|
||||
data = sectNameTab.toString().getBytes();
|
||||
}
|
||||
else {
|
||||
data = sectData;
|
||||
section.putLong(Elf64_Shdr.sh_size.off, sectData.length);
|
||||
}
|
||||
|
||||
section.putLong(Elf64_Shdr.sh_entsize.off, 0);
|
||||
|
||||
// Determine the alignment and entrysize
|
||||
// based on type of section
|
||||
switch (sectType) {
|
||||
case Elf64_Shdr.SHT_PROGBITS:
|
||||
if ((sectFlags & Elf64_Shdr.SHF_EXECINSTR) != 0)
|
||||
align = 16;
|
||||
else
|
||||
align = 4;
|
||||
break;
|
||||
case Elf64_Shdr.SHT_SYMTAB:
|
||||
align = 8;
|
||||
section.putLong(Elf64_Shdr.sh_entsize.off, Elf64_Sym.totalsize);
|
||||
break;
|
||||
case Elf64_Shdr.SHT_STRTAB:
|
||||
align = 1;
|
||||
break;
|
||||
case Elf64_Shdr.SHT_RELA:
|
||||
align = 8;
|
||||
section.putLong(Elf64_Shdr.sh_entsize.off, Elf64_Rela.totalsize);
|
||||
break;
|
||||
case Elf64_Shdr.SHT_REL:
|
||||
align = 8;
|
||||
section.putLong(Elf64_Shdr.sh_entsize.off, Elf64_Rel.totalsize);
|
||||
break;
|
||||
case Elf64_Shdr.SHT_NOBITS:
|
||||
align = 4;
|
||||
break;
|
||||
default:
|
||||
align = 8;
|
||||
break;
|
||||
}
|
||||
section.putLong(Elf64_Shdr.sh_addralign.off, align);
|
||||
|
||||
hasrelocations = hasRelocations;
|
||||
sectionIndex = sectIndex;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return section.getLong(Elf64_Shdr.sh_size.off);
|
||||
}
|
||||
|
||||
public int getDataAlign() {
|
||||
return ((int)section.getLong(Elf64_Shdr.sh_addralign.off));
|
||||
}
|
||||
|
||||
// Alignment requirements for the Elf64_Shdr structures
|
||||
public static int getShdrAlign() {
|
||||
return (4);
|
||||
}
|
||||
|
||||
public byte[] getArray() {
|
||||
return section.array();
|
||||
}
|
||||
|
||||
public byte[] getDataArray() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setOffset(long offset) {
|
||||
section.putLong(Elf64_Shdr.sh_offset.off, offset);
|
||||
}
|
||||
|
||||
public void setLink(int link) {
|
||||
section.putInt(Elf64_Shdr.sh_link.off, link);
|
||||
}
|
||||
|
||||
public void setInfo(int info) {
|
||||
section.putInt(Elf64_Shdr.sh_info.off, info);
|
||||
}
|
||||
|
||||
public long getOffset() {
|
||||
return (section.getLong(Elf64_Shdr.sh_offset.off));
|
||||
}
|
||||
|
||||
public boolean hasRelocations() {
|
||||
return hasrelocations;
|
||||
}
|
||||
|
||||
public int getSectionId() {
|
||||
return sectionIndex;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.elf;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.tools.jaotc.binformat.NativeSymbol;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
|
||||
import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
|
||||
|
||||
public class ElfSymbol extends NativeSymbol {
|
||||
ByteBuffer sym;
|
||||
|
||||
public ElfSymbol(int symbolindex, int strindex, byte type, byte bind,
|
||||
byte sectindex, long offset, long size) {
|
||||
super(symbolindex);
|
||||
sym = ElfByteBuffer.allocate(Elf64_Sym.totalsize);
|
||||
|
||||
sym.putInt(Elf64_Sym.st_name.off, strindex);
|
||||
sym.put(Elf64_Sym.st_info.off, Elf64_Sym.ELF64_ST_INFO(bind, type));
|
||||
sym.put(Elf64_Sym.st_other.off, (byte)0);
|
||||
// Section indexes start at 1 but we manage the index internally
|
||||
// as 0 relative
|
||||
sym.putChar(Elf64_Sym.st_shndx.off, (char)(sectindex));
|
||||
sym.putLong(Elf64_Sym.st_value.off, offset);
|
||||
sym.putLong(Elf64_Sym.st_size.off, size);
|
||||
}
|
||||
|
||||
public byte[] getArray() {
|
||||
return sym.array();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.elf;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import jdk.tools.jaotc.binformat.elf.Elf;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym;
|
||||
import jdk.tools.jaotc.binformat.elf.ElfSymbol;
|
||||
import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
|
||||
|
||||
public class ElfSymtab {
|
||||
|
||||
ArrayList<ElfSymbol>localSymbols = new ArrayList<ElfSymbol>();
|
||||
ArrayList<ElfSymbol>globalSymbols = new ArrayList<ElfSymbol>();
|
||||
|
||||
/**
|
||||
* number of symbols added
|
||||
*/
|
||||
int symbolCount;
|
||||
|
||||
/**
|
||||
* String holding symbol table strings
|
||||
*/
|
||||
private StringBuilder strTabContent = new StringBuilder();
|
||||
|
||||
/**
|
||||
* Keeps track of bytes in string table since strTabContent.length()
|
||||
* is number of chars, not bytes.
|
||||
*/
|
||||
private int strTabNrOfBytes = 0;
|
||||
|
||||
public ElfSymtab() {
|
||||
symbolCount = 0;
|
||||
}
|
||||
|
||||
public ElfSymbol addSymbolEntry(String name, byte type, byte bind,
|
||||
byte secHdrIndex, long offset, long size) {
|
||||
// Get the current symbol index and append symbol name to string table.
|
||||
int index;
|
||||
ElfSymbol sym;
|
||||
|
||||
if (name.isEmpty()) {
|
||||
index = 0;
|
||||
strTabContent.append('\0');
|
||||
strTabNrOfBytes += 1;
|
||||
sym = new ElfSymbol(symbolCount, index, type, bind, secHdrIndex, offset, size);
|
||||
localSymbols.add(sym);
|
||||
} else {
|
||||
// We can't trust strTabContent.length() since that is
|
||||
// chars (UTF16), keep track of bytes on our own.
|
||||
index = strTabNrOfBytes;
|
||||
// strTabContent.append("_").append(name).append('\0');
|
||||
strTabContent.append(name).append('\0');
|
||||
// + 1 for null, + 1 for "_"
|
||||
//strTabNrOfBytes += (name.getBytes().length + 1 + 1);
|
||||
strTabNrOfBytes += (name.getBytes().length + 1);
|
||||
|
||||
sym = new ElfSymbol(symbolCount, index, type, bind, secHdrIndex, offset, size);
|
||||
if ((bind & Elf64_Sym.STB_GLOBAL) != 0)
|
||||
globalSymbols.add(sym);
|
||||
else
|
||||
localSymbols.add(sym);
|
||||
}
|
||||
symbolCount++;
|
||||
return (sym);
|
||||
}
|
||||
|
||||
// Update the symbol indexes once all symbols have been added.
|
||||
// This is required since we'll be reordering the symbols in the
|
||||
// file to be in the order of Local then global.
|
||||
public void updateIndexes() {
|
||||
int index = 0;
|
||||
|
||||
// Update the local symbol indexes
|
||||
for (int i = 0; i < localSymbols.size(); i++ ) {
|
||||
ElfSymbol sym = localSymbols.get(i);
|
||||
sym.setIndex(index++);
|
||||
}
|
||||
|
||||
// Update the global symbol indexes
|
||||
for (int i = 0; i < globalSymbols.size(); i++ ) {
|
||||
ElfSymbol sym = globalSymbols.get(i);
|
||||
sym.setIndex(index++);
|
||||
}
|
||||
}
|
||||
|
||||
public int getNumLocalSyms() { return localSymbols.size(); }
|
||||
public int getNumGlobalSyms() { return globalSymbols.size(); }
|
||||
|
||||
|
||||
// Create a single byte array that contains the symbol table entries
|
||||
public byte[] getSymtabArray() {
|
||||
int index = 0;
|
||||
ByteBuffer symtabData = ElfByteBuffer.allocate(symbolCount*Elf64_Sym.totalsize);
|
||||
byte [] retarray;
|
||||
|
||||
updateIndexes();
|
||||
|
||||
// Add the local symbols
|
||||
for (int i = 0; i < localSymbols.size(); i++ ) {
|
||||
ElfSymbol sym = localSymbols.get(i);
|
||||
byte [] arr = sym.getArray();
|
||||
symtabData.put(arr);
|
||||
}
|
||||
// Add the global symbols
|
||||
for (int i = 0; i < globalSymbols.size(); i++ ) {
|
||||
ElfSymbol sym = globalSymbols.get(i);
|
||||
byte [] arr = sym.getArray();
|
||||
symtabData.put(arr);
|
||||
}
|
||||
retarray = symtabData.array();
|
||||
|
||||
return (retarray);
|
||||
}
|
||||
|
||||
// Return the string table array
|
||||
public byte[] getStrtabArray() {
|
||||
byte [] strs = strTabContent.toString().getBytes();
|
||||
return (strs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.elf;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
|
||||
|
||||
/**
|
||||
* Class that abstracts MACH-O target details.
|
||||
*
|
||||
*/
|
||||
public class ElfTargetInfo {
|
||||
/**
|
||||
* Target architecture.
|
||||
*/
|
||||
private static final char arch;
|
||||
|
||||
/**
|
||||
* Architecture endian-ness.
|
||||
*/
|
||||
private static final int endian = Elf64_Ehdr.ELFDATA2LSB;
|
||||
|
||||
/**
|
||||
* Target OS string.
|
||||
*/
|
||||
private static String osName;
|
||||
|
||||
static {
|
||||
// Find the target arch details
|
||||
String archStr = System.getProperty("os.arch").toLowerCase();
|
||||
if (ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN) {
|
||||
System.out.println("Only Little Endian byte order supported!");
|
||||
}
|
||||
|
||||
if (archStr.equals("amd64") || archStr.equals("x86_64")) {
|
||||
arch = Elf64_Ehdr.EM_X86_64;
|
||||
} else {
|
||||
System.out.println("Unsupported architecture " + archStr);
|
||||
arch = Elf64_Ehdr.EM_NONE;
|
||||
}
|
||||
|
||||
osName = System.getProperty("os.name").toLowerCase();
|
||||
if (!osName.equals("linux") && !osName.equals("sunos")) {
|
||||
System.out.println("Unsupported Operating System " + osName);
|
||||
osName = "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
public static char getElfArch() {
|
||||
return arch;
|
||||
}
|
||||
|
||||
public static int getElfEndian() {
|
||||
return endian;
|
||||
}
|
||||
|
||||
public static String getOsName() {
|
||||
return osName;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,6 +30,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.tools.jaotc.binformat.Container;
|
||||
import jdk.tools.jaotc.binformat.BinaryContainer;
|
||||
import jdk.tools.jaotc.binformat.ByteContainer;
|
||||
import jdk.tools.jaotc.binformat.CodeContainer;
|
||||
@ -37,36 +38,60 @@ import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
|
||||
import jdk.tools.jaotc.binformat.Relocation;
|
||||
import jdk.tools.jaotc.binformat.Relocation.RelocType;
|
||||
import jdk.tools.jaotc.binformat.Symbol;
|
||||
import jdk.tools.jaotc.binformat.NativeSymbol;
|
||||
import jdk.tools.jaotc.binformat.Symbol.Binding;
|
||||
import jdk.tools.jaotc.binformat.Symbol.Kind;
|
||||
import jdk.tools.jaotc.jnilibelf.ELFContainer;
|
||||
import jdk.tools.jaotc.jnilibelf.ELFSymbol;
|
||||
import jdk.tools.jaotc.jnilibelf.JNIELFContainer;
|
||||
import jdk.tools.jaotc.jnilibelf.JNIELFRelocation;
|
||||
import jdk.tools.jaotc.jnilibelf.JNIELFTargetInfo;
|
||||
import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.ELF;
|
||||
import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.LibELF.Elf_Cmd;
|
||||
import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.LibELF.Elf_Type;
|
||||
import jdk.tools.jaotc.jnilibelf.Pointer;
|
||||
|
||||
import jdk.tools.jaotc.binformat.elf.Elf;
|
||||
import jdk.tools.jaotc.binformat.elf.ElfSymbol;
|
||||
import jdk.tools.jaotc.binformat.elf.ElfTargetInfo;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Shdr;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rel;
|
||||
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela;
|
||||
|
||||
public class JELFRelocObject {
|
||||
|
||||
private final BinaryContainer binContainer;
|
||||
|
||||
private final JNIELFContainer elfContainer;
|
||||
private final ElfContainer elfContainer;
|
||||
|
||||
private final int segmentSize;
|
||||
|
||||
public JELFRelocObject(BinaryContainer binContainer, String outputFileName, String aotVersion) {
|
||||
this.binContainer = binContainer;
|
||||
this.elfContainer = new JNIELFContainer(outputFileName, aotVersion);
|
||||
this.elfContainer = new ElfContainer(outputFileName, aotVersion);
|
||||
this.segmentSize = binContainer.getCodeSegmentSize();
|
||||
}
|
||||
|
||||
private void createByteSection(ByteContainer c, int scnFlags) {
|
||||
private ElfSection createByteSection(ArrayList<ElfSection>sections,
|
||||
String sectName,
|
||||
byte [] scnData,
|
||||
boolean hasRelocs,
|
||||
int scnFlags,
|
||||
int scnType) {
|
||||
|
||||
ElfSection sect = new ElfSection(sectName,
|
||||
scnData,
|
||||
scnFlags,
|
||||
scnType,
|
||||
hasRelocs,
|
||||
sections.size());
|
||||
// Add this section to our list
|
||||
sections.add(sect);
|
||||
|
||||
return (sect);
|
||||
}
|
||||
|
||||
private void createByteSection(ArrayList<ElfSection>sections,
|
||||
ByteContainer c, int scnFlags) {
|
||||
ElfSection sect;
|
||||
boolean hasRelocs = c.hasRelocations();
|
||||
byte[] scnData = c.getByteArray();
|
||||
int scnType = ELF.SHT_PROGBITS;
|
||||
boolean zeros = !c.hasRelocations();
|
||||
|
||||
int scnType = Elf64_Shdr.SHT_PROGBITS;
|
||||
boolean zeros = hasRelocs;
|
||||
if (zeros) {
|
||||
for (byte b : scnData) {
|
||||
if (b != 0) {
|
||||
@ -75,30 +100,30 @@ public class JELFRelocObject {
|
||||
}
|
||||
}
|
||||
if (zeros) {
|
||||
scnType = ELF.SHT_NOBITS;
|
||||
scnType = Elf64_Shdr.SHT_NOBITS;
|
||||
}
|
||||
}
|
||||
|
||||
int sectionId = elfContainer.createSection(c.getContainerName(), scnData, Elf_Type.ELF_T_BYTE, segmentSize, scnType, scnFlags, ELF.SHN_UNDEF, 0);
|
||||
c.setSectionId(sectionId);
|
||||
// Clear out code section data to allow for GC
|
||||
c.clear();
|
||||
sect = createByteSection(sections, c.getContainerName(),
|
||||
scnData, hasRelocs,
|
||||
scnFlags, scnType);
|
||||
c.setSectionId(sect.getSectionId());
|
||||
}
|
||||
|
||||
private void createCodeSection(CodeContainer c) {
|
||||
createByteSection(c, ELF.SHF_ALLOC | ELF.SHF_EXECINSTR);
|
||||
private void createCodeSection(ArrayList<ElfSection>sections, CodeContainer c) {
|
||||
createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC | Elf64_Shdr.SHF_EXECINSTR);
|
||||
}
|
||||
|
||||
private void createReadOnlySection(ReadOnlyDataContainer c) {
|
||||
createByteSection(c, ELF.SHF_ALLOC);
|
||||
private void createReadOnlySection(ArrayList<ElfSection>sections, ReadOnlyDataContainer c) {
|
||||
createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC);
|
||||
}
|
||||
|
||||
private void createReadWriteSection(ByteContainer c) {
|
||||
createByteSection(c, ELF.SHF_ALLOC | ELF.SHF_WRITE);
|
||||
private void createReadWriteSection(ArrayList<ElfSection>sections, ByteContainer c) {
|
||||
createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC | Elf64_Shdr.SHF_WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ELF relocatable object using jdk.tools.jaotc.jnilibelf API.
|
||||
* Create an ELF relocatable object
|
||||
*
|
||||
* @param relocationTable
|
||||
* @param symbols
|
||||
@ -106,145 +131,171 @@ public class JELFRelocObject {
|
||||
*/
|
||||
public void createELFRelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException {
|
||||
// Allocate ELF Header
|
||||
elfContainer.createELFHeader(ELF.ET_REL);
|
||||
ElfHeader eh = new ElfHeader();
|
||||
|
||||
ArrayList<ElfSection> sections = new ArrayList<ElfSection>();
|
||||
|
||||
// Create the null section
|
||||
createByteSection(sections, null, null, false, 0, 0);
|
||||
|
||||
// Create text section
|
||||
createCodeSection(binContainer.getCodeContainer());
|
||||
createReadOnlySection(binContainer.getMetaspaceNamesContainer());
|
||||
createReadOnlySection(binContainer.getKlassesOffsetsContainer());
|
||||
createReadOnlySection(binContainer.getMethodsOffsetsContainer());
|
||||
createReadOnlySection(binContainer.getKlassesDependenciesContainer());
|
||||
createReadWriteSection(binContainer.getMetaspaceGotContainer());
|
||||
createReadWriteSection(binContainer.getMetadataGotContainer());
|
||||
createReadWriteSection(binContainer.getMethodStateContainer());
|
||||
createReadWriteSection(binContainer.getOopGotContainer());
|
||||
createReadWriteSection(binContainer.getMethodMetadataContainer());
|
||||
createReadOnlySection(binContainer.getStubsOffsetsContainer());
|
||||
createReadOnlySection(binContainer.getHeaderContainer().getContainer());
|
||||
createReadOnlySection(binContainer.getCodeSegmentsContainer());
|
||||
createReadOnlySection(binContainer.getConstantDataContainer());
|
||||
createReadOnlySection(binContainer.getConfigContainer());
|
||||
createCodeSection(sections, binContainer.getCodeContainer());
|
||||
createReadOnlySection(sections, binContainer.getMetaspaceNamesContainer());
|
||||
createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer());
|
||||
createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer());
|
||||
createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer());
|
||||
createReadWriteSection(sections, binContainer.getMetaspaceGotContainer());
|
||||
createReadWriteSection(sections, binContainer.getMetadataGotContainer());
|
||||
createReadWriteSection(sections, binContainer.getMethodStateContainer());
|
||||
createReadWriteSection(sections, binContainer.getOopGotContainer());
|
||||
createReadWriteSection(sections, binContainer.getMethodMetadataContainer());
|
||||
createReadOnlySection(sections, binContainer.getStubsOffsetsContainer());
|
||||
createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer());
|
||||
createReadOnlySection(sections, binContainer.getCodeSegmentsContainer());
|
||||
createReadOnlySection(sections, binContainer.getConstantDataContainer());
|
||||
createReadOnlySection(sections, binContainer.getConfigContainer());
|
||||
|
||||
// createExternalLinkage();
|
||||
|
||||
createCodeSection(binContainer.getExtLinkageContainer());
|
||||
createReadWriteSection(binContainer.getExtLinkageGOTContainer());
|
||||
createCodeSection(sections, binContainer.getExtLinkageContainer());
|
||||
createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer());
|
||||
|
||||
// Get ELF symbol data from BinaryContainer object's symbol tables
|
||||
createELFSymbolTables(symbols);
|
||||
ElfSymtab symtab = createELFSymbolTables(sections, symbols);
|
||||
|
||||
// Create string table section and symbol table sections in
|
||||
// that order since symtab section needs to set the index of strtab in sh_link field
|
||||
int strTabSectionIndex = elfContainer.createSection(".strtab", elfContainer.getStrTabContent().getBytes(StandardCharsets.UTF_8), Elf_Type.ELF_T_BYTE, 1, ELF.SHT_STRTAB, 0, ELF.SHN_UNDEF, 0);
|
||||
// that order since symtab section needs to set the index of
|
||||
// strtab in sh_link field
|
||||
ElfSection strTabSection = createByteSection(sections,
|
||||
".strtab",
|
||||
symtab.getStrtabArray(),
|
||||
false,
|
||||
0,
|
||||
Elf64_Shdr.SHT_STRTAB);
|
||||
|
||||
// Now create .symtab section with the symtab data constructed. On Linux, sh_link of symtab
|
||||
// contains the index of string table its symbols reference and
|
||||
// sh_info contains the index of first non-local symbol
|
||||
int scnInfo = elfContainer.getFirstNonLocalSymbolIndex();
|
||||
int symTabSectionIndex = elfContainer.createSection(".symtab", getELFSymbolTableData(), Elf_Type.ELF_T_SYM, 8, ELF.SHT_SYMTAB, ELF.SHF_ALLOC, strTabSectionIndex, scnInfo);
|
||||
// Now create .symtab section with the symtab data constructed.
|
||||
// On Linux, sh_link of symtab contains the index of string table
|
||||
// its symbols reference and sh_info contains the index of first
|
||||
// non-local symbol
|
||||
ElfSection symTabSection = createByteSection(sections,
|
||||
".symtab",
|
||||
symtab.getSymtabArray(),
|
||||
false,
|
||||
0,
|
||||
Elf64_Shdr.SHT_SYMTAB);
|
||||
symTabSection.setLink(strTabSection.getSectionId());
|
||||
symTabSection.setInfo(symtab.getNumLocalSyms());
|
||||
|
||||
buildRelocations(relocationTable, symTabSectionIndex);
|
||||
ElfRelocTable elfRelocTable = createElfRelocTable(sections,
|
||||
relocationTable);
|
||||
|
||||
createElfRelocSections(sections, elfRelocTable, symTabSection.getSectionId());
|
||||
|
||||
// Now, finally, after creating all sections, create shstrtab section
|
||||
elfContainer.createSection(".shstrtab", elfContainer.getShStrTabContent().getBytes(StandardCharsets.UTF_8), Elf_Type.ELF_T_BYTE, 1, ELF.SHT_STRTAB, 0, ELF.SHN_UNDEF, 0);
|
||||
ElfSection shStrTabSection = createByteSection(sections,
|
||||
".shstrtab",
|
||||
null,
|
||||
false,
|
||||
0,
|
||||
Elf64_Shdr.SHT_STRTAB);
|
||||
eh.setSectionStrNdx(shStrTabSection.getSectionId());
|
||||
|
||||
// Run elf_update
|
||||
elfContainer.elfUpdate(Elf_Cmd.ELF_C_NULL);
|
||||
// Update all section offsets and the Elf header section offset
|
||||
// Write the Header followed by the contents of each section
|
||||
// and then the section structures (section table).
|
||||
int file_offset = Elf64_Ehdr.totalsize;
|
||||
|
||||
// Run elfUpdate again to write it out.
|
||||
elfContainer.elfUpdate(Elf_Cmd.ELF_C_WRITE);
|
||||
// Finish ELF processing
|
||||
elfContainer.elfEnd();
|
||||
// and round it up
|
||||
file_offset = (file_offset + (sections.get(1).getDataAlign()-1)) &
|
||||
~((sections.get(1).getDataAlign()-1));
|
||||
|
||||
// Calc file offsets for section data skipping null section
|
||||
for (int i = 1; i < sections.size(); i++) {
|
||||
ElfSection sect = sections.get(i);
|
||||
file_offset = (file_offset + (sect.getDataAlign()-1)) &
|
||||
~((sect.getDataAlign()-1));
|
||||
sect.setOffset(file_offset);
|
||||
file_offset += sect.getSize();
|
||||
}
|
||||
|
||||
// Align the section table
|
||||
file_offset = (file_offset + (ElfSection.getShdrAlign()-1)) &
|
||||
~((ElfSection.getShdrAlign()-1));
|
||||
|
||||
// Update the Elf Header with the offset of the first Elf64_Shdr
|
||||
// and the number of sections.
|
||||
eh.setSectionOff(file_offset);
|
||||
eh.setSectionNum(sections.size());
|
||||
|
||||
// Write out the Header
|
||||
elfContainer.writeBytes(eh.getArray());
|
||||
|
||||
// Write out each section contents skipping null section
|
||||
for (int i = 1; i < sections.size(); i++) {
|
||||
ElfSection sect = sections.get(i);
|
||||
elfContainer.writeBytes(sect.getDataArray(), sect.getDataAlign());
|
||||
}
|
||||
|
||||
// Write out the section table
|
||||
for (int i = 0; i < sections.size(); i++) {
|
||||
ElfSection sect = sections.get(i);
|
||||
elfContainer.writeBytes(sect.getArray(), ElfSection.getShdrAlign());
|
||||
}
|
||||
|
||||
elfContainer.close();
|
||||
}
|
||||
|
||||
private void buildRelocations(Map<Symbol, List<Relocation>> relocationTable, final int symTabSectionIndex) {
|
||||
/*
|
||||
* Create relocation sections. This needs to be done after symbol table sections were
|
||||
* created since relocation entries will need indices of sections to which they apply.
|
||||
*/
|
||||
createELFRelocationTables(relocationTable);
|
||||
createAllRelocationSections(new SymTabELFContainer(symTabSectionIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct ELF symbol data from BinaryContainer object's symbol tables. Both dynamic ELF
|
||||
* symbol table and ELF symbol table are created from BinaryContainer's symbol info.
|
||||
*
|
||||
* @param symbols
|
||||
*/
|
||||
private void createELFSymbolTables(Collection<Symbol> symbols) {
|
||||
private ElfSymtab createELFSymbolTables(ArrayList<ElfSection> sections, Collection<Symbol> symbols) {
|
||||
ElfSymtab symtab = new ElfSymtab();
|
||||
|
||||
// First, create the initial null symbol. This is a local symbol.
|
||||
elfContainer.createELFSymbolEntry("", 0, 0, ELF.SHN_UNDEF, 0, 0, true);
|
||||
symtab.addSymbolEntry("", (byte)0, (byte)0, Elf64_Shdr.SHN_UNDEF, 0, 0);
|
||||
|
||||
// Now create ELF symbol entries for all symbols.
|
||||
for (Symbol symbol : symbols) {
|
||||
// Get the index of section this symbol is defined in.
|
||||
int secHdrIndex = symbol.getSection().getSectionId();
|
||||
boolean isLocal = (symbol.getBinding() == Binding.LOCAL);
|
||||
ELFSymbol elfSymbol = elfContainer.createELFSymbolEntry(symbol.getName(), getELFTypeOf(symbol), getELFBindOf(symbol), secHdrIndex, symbol.getSize(), symbol.getOffset(), isLocal);
|
||||
symbol.setElfSymbol(elfSymbol);
|
||||
ElfSymbol elfSymbol = symtab.addSymbolEntry(symbol.getName(), getELFTypeOf(symbol), getELFBindOf(symbol), (byte)secHdrIndex, symbol.getOffset(), symbol.getSize());
|
||||
symbol.setNativeSymbol((NativeSymbol)elfSymbol);
|
||||
}
|
||||
return (symtab);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct ELF symbol data from BinaryContainer object's symbol tables.
|
||||
*
|
||||
* @return a byte array containing the symbol table
|
||||
*/
|
||||
private byte[] getELFSymbolTableData() {
|
||||
final int entrySize = JNIELFTargetInfo.sizeOfSymtabEntry();
|
||||
|
||||
// First, add all local symbols.
|
||||
List<ELFSymbol> localSymbols = elfContainer.getLocalSymbols();
|
||||
List<ELFSymbol> globalSymbols = elfContainer.getGlobalSymbols();
|
||||
|
||||
int localSymCount = localSymbols.size();
|
||||
int globalSymCount = globalSymbols.size();
|
||||
byte[] sectionDataArray = new byte[(localSymCount + globalSymCount) * entrySize];
|
||||
|
||||
for (int i = 0; i < localSymCount; i++) {
|
||||
ELFSymbol symbol = localSymbols.get(i);
|
||||
Pointer address = symbol.getAddress();
|
||||
address.copyBytesTo(sectionDataArray, entrySize, i * entrySize);
|
||||
}
|
||||
|
||||
// Next, add all global symbols.
|
||||
|
||||
for (int i = 0; i < globalSymCount; i++) {
|
||||
ELFSymbol symbol = globalSymbols.get(i);
|
||||
Pointer address = symbol.getAddress();
|
||||
address.copyBytesTo(sectionDataArray, entrySize, (localSymCount + i) * entrySize);
|
||||
}
|
||||
|
||||
return sectionDataArray;
|
||||
}
|
||||
|
||||
private static int getELFTypeOf(Symbol sym) {
|
||||
private static byte getELFTypeOf(Symbol sym) {
|
||||
Kind kind = sym.getKind();
|
||||
if (kind == Symbol.Kind.NATIVE_FUNCTION || kind == Symbol.Kind.JAVA_FUNCTION) {
|
||||
return ELF.STT_FUNC;
|
||||
return Elf64_Sym.STT_FUNC;
|
||||
} else if (kind == Symbol.Kind.OBJECT) {
|
||||
return ELF.STT_OBJECT;
|
||||
return Elf64_Sym.STT_OBJECT;
|
||||
}
|
||||
return ELF.STT_NOTYPE;
|
||||
return Elf64_Sym.STT_NOTYPE;
|
||||
}
|
||||
|
||||
private static int getELFBindOf(Symbol sym) {
|
||||
private static byte getELFBindOf(Symbol sym) {
|
||||
Binding binding = sym.getBinding();
|
||||
if (binding == Symbol.Binding.GLOBAL) {
|
||||
return ELF.STB_GLOBAL;
|
||||
return Elf64_Sym.STB_GLOBAL;
|
||||
}
|
||||
return ELF.STB_LOCAL;
|
||||
return Elf64_Sym.STB_LOCAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct ELF relocation section data from BinaryContainer object's relocation tables.
|
||||
* Construct a Elf relocation table from BinaryContainer object's relocation tables.
|
||||
*
|
||||
* @param sections
|
||||
* @param relocationTable
|
||||
*/
|
||||
private void createELFRelocationTables(Map<Symbol, List<Relocation>> relocationTable) {
|
||||
private ElfRelocTable createElfRelocTable(ArrayList<ElfSection> sections,
|
||||
Map<Symbol, List<Relocation>> relocationTable) {
|
||||
|
||||
ElfRelocTable elfRelocTable = new ElfRelocTable(sections.size());
|
||||
/*
|
||||
* For each of the symbols with associated relocation records, create an ELF relocation
|
||||
* For each of the symbols with associated relocation records, create a Elf relocation
|
||||
* entry.
|
||||
*/
|
||||
for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) {
|
||||
@ -252,18 +303,26 @@ public class JELFRelocObject {
|
||||
Symbol symbol = entry.getKey();
|
||||
|
||||
for (Relocation reloc : relocs) {
|
||||
createRelocation(symbol, reloc);
|
||||
createRelocation(symbol, reloc, elfRelocTable);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) {
|
||||
createRelocation(entry.getKey(), entry.getValue());
|
||||
createRelocation(entry.getKey(), entry.getValue(), elfRelocTable);
|
||||
}
|
||||
|
||||
return (elfRelocTable);
|
||||
}
|
||||
|
||||
private void createRelocation(Symbol symbol, Relocation reloc) {
|
||||
private void createRelocation(Symbol symbol, Relocation reloc, ElfRelocTable elfRelocTable) {
|
||||
RelocType relocType = reloc.getType();
|
||||
|
||||
int elfRelocType = getELFRelocationType(relocType);
|
||||
ElfSymbol sym = (ElfSymbol)symbol.getNativeSymbol();
|
||||
int symno = sym.getIndex();
|
||||
int sectindex = reloc.getSection().getSectionId();
|
||||
int offset = reloc.getOffset();
|
||||
int addend = 0;
|
||||
|
||||
switch (relocType) {
|
||||
case FOREIGN_CALL_DIRECT:
|
||||
@ -271,85 +330,89 @@ public class JELFRelocObject {
|
||||
case STUB_CALL_DIRECT:
|
||||
case FOREIGN_CALL_INDIRECT_GOT: {
|
||||
// Create relocation entry
|
||||
int addend = -4; // Size in bytes of the patch location
|
||||
// System.out.println("getELFRelocationType: PLT relocation type using X86_64_RELOC_BRANCH");
|
||||
addend = -4; // Size in bytes of the patch location
|
||||
// Relocation should be applied at the location after call operand
|
||||
int offset = reloc.getOffset() + reloc.getSize() + addend;
|
||||
elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol());
|
||||
offset = offset + reloc.getSize() + addend;
|
||||
break;
|
||||
}
|
||||
case FOREIGN_CALL_DIRECT_FAR: {
|
||||
// Create relocation entry
|
||||
int addend = -8; // Size in bytes of the patch location
|
||||
addend = -8; // Size in bytes of the patch location
|
||||
// Relocation should be applied at the location after call operand
|
||||
// 10 = 2 (jmp [r]) + 8 (imm64)
|
||||
int offset = reloc.getOffset() + reloc.getSize() + addend - 2;
|
||||
elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol());
|
||||
offset = offset + reloc.getSize() + addend - 2;
|
||||
break;
|
||||
}
|
||||
case FOREIGN_CALL_INDIRECT:
|
||||
case JAVA_CALL_INDIRECT:
|
||||
case STUB_CALL_INDIRECT: {
|
||||
// Do nothing.
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case EXTERNAL_DATA_REFERENCE_FAR: {
|
||||
// Create relocation entry
|
||||
int addend = -4; // Size of 32-bit address of the GOT
|
||||
addend = -4; // Size of 32-bit address of the GOT
|
||||
/*
|
||||
* Relocation should be applied before the test instruction to the move instruction.
|
||||
* reloc.getOffset() points to the test instruction after the instruction that loads
|
||||
* offset points to the test instruction after the instruction that loads
|
||||
* the address of polling page. So set the offset appropriately.
|
||||
*/
|
||||
int offset = reloc.getOffset() + addend;
|
||||
elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol());
|
||||
offset = offset + addend;
|
||||
break;
|
||||
}
|
||||
case METASPACE_GOT_REFERENCE:
|
||||
case EXTERNAL_PLT_TO_GOT:
|
||||
case STATIC_STUB_TO_STATIC_METHOD:
|
||||
case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: {
|
||||
int addend = -4; // Size of 32-bit address of the GOT
|
||||
addend = -4; // Size of 32-bit address of the GOT
|
||||
/*
|
||||
* Relocation should be applied before the test instruction to the move instruction.
|
||||
* reloc.getOffset() points to the test instruction after the instruction that loads
|
||||
* the address of polling page. So set the offset appropriately.
|
||||
* Relocation should be applied before the test instruction to
|
||||
* the move instruction. reloc.getOffset() points to the
|
||||
* test instruction after the instruction that loads the
|
||||
* address of polling page. So set the offset appropriately.
|
||||
*/
|
||||
int offset = reloc.getOffset() + addend;
|
||||
elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol());
|
||||
offset = offset + addend;
|
||||
break;
|
||||
}
|
||||
case EXTERNAL_GOT_TO_PLT:
|
||||
case LOADTIME_ADDRESS: {
|
||||
// this is load time relocations
|
||||
elfContainer.createELFRelocationEntry(reloc.getSection(), reloc.getOffset(), elfRelocType, 0, symbol.getElfSymbol());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new InternalError("Unhandled relocation type: " + relocType);
|
||||
}
|
||||
elfRelocTable.createRelocationEntry(sectindex, offset, symno, elfRelocType, addend);
|
||||
}
|
||||
|
||||
// TODO: Populate the mapping of RelocType to ELF relocation types
|
||||
private static int getELFRelocationType(RelocType relocType) {
|
||||
int elfRelocType = 0; // R_<ARCH>_NONE if #define'd to 0 for all values of ARCH
|
||||
switch (JNIELFTargetInfo.getELFArch()) {
|
||||
case ELF.EM_X64_64:
|
||||
switch (ElfTargetInfo.getElfArch()) {
|
||||
case Elf64_Ehdr.EM_X86_64:
|
||||
// Return R_X86_64_* entries based on relocType
|
||||
if (relocType == RelocType.FOREIGN_CALL_DIRECT || relocType == RelocType.JAVA_CALL_DIRECT || relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
|
||||
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_PLT32;
|
||||
if (relocType == RelocType.FOREIGN_CALL_DIRECT ||
|
||||
relocType == RelocType.JAVA_CALL_DIRECT ||
|
||||
relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
|
||||
elfRelocType = Elf64_Rela.R_X86_64_PLT32;
|
||||
} else if (relocType == RelocType.STUB_CALL_DIRECT) {
|
||||
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_PC32;
|
||||
elfRelocType = Elf64_Rela.R_X86_64_PC32;
|
||||
} else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) {
|
||||
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_64;
|
||||
} else if (relocType == RelocType.FOREIGN_CALL_INDIRECT || relocType == RelocType.JAVA_CALL_INDIRECT || relocType == RelocType.STUB_CALL_INDIRECT) {
|
||||
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_NONE;
|
||||
elfRelocType = Elf64_Rela.R_X86_64_64;
|
||||
} else if (relocType == RelocType.FOREIGN_CALL_INDIRECT ||
|
||||
relocType == RelocType.JAVA_CALL_INDIRECT ||
|
||||
relocType == RelocType.STUB_CALL_INDIRECT) {
|
||||
elfRelocType = Elf64_Rela.R_X86_64_NONE;
|
||||
} else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) {
|
||||
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_GOTPCREL;
|
||||
} else if (relocType == RelocType.METASPACE_GOT_REFERENCE || relocType == RelocType.EXTERNAL_PLT_TO_GOT || relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD ||
|
||||
relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) {
|
||||
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_PC32;
|
||||
} else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT || relocType == RelocType.LOADTIME_ADDRESS) {
|
||||
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_64;
|
||||
elfRelocType = Elf64_Rela.R_X86_64_GOTPCREL;
|
||||
} else if (relocType == RelocType.METASPACE_GOT_REFERENCE ||
|
||||
relocType == RelocType.EXTERNAL_PLT_TO_GOT ||
|
||||
relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD ||
|
||||
relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) {
|
||||
elfRelocType = Elf64_Rela.R_X86_64_PC32;
|
||||
} else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT ||
|
||||
relocType == RelocType.LOADTIME_ADDRESS) {
|
||||
elfRelocType = Elf64_Rela.R_X86_64_64;
|
||||
} else {
|
||||
assert false : "Unhandled relocation type: " + relocType;
|
||||
}
|
||||
@ -360,61 +423,26 @@ public class JELFRelocObject {
|
||||
return elfRelocType;
|
||||
}
|
||||
|
||||
private void createAllRelocationSections(ELFContainer symtab) {
|
||||
for (Map.Entry<ELFContainer, ArrayList<Pointer>> entry : elfContainer.getRelocTables().entrySet()) {
|
||||
createRelocationSection(entry.getKey(), entry.getValue(), symtab);
|
||||
}
|
||||
}
|
||||
private void createElfRelocSections(ArrayList<ElfSection> sections,
|
||||
ElfRelocTable elfRelocTable,
|
||||
int symtabsectidx) {
|
||||
|
||||
private void createRelocationSection(ELFContainer container, ArrayList<Pointer> relocations, ELFContainer symtab) {
|
||||
String secName = container.getContainerName();
|
||||
int entrySize = JNIELFTargetInfo.sizeOfRelocEntry();
|
||||
int numEntries = relocations.size();
|
||||
byte[] sectionDataBytes = new byte[numEntries * entrySize];
|
||||
// Grab count before we create new sections
|
||||
int count = sections.size();
|
||||
|
||||
for (int index = 0; index < relocations.size(); index++) {
|
||||
Pointer entry = relocations.get(index);
|
||||
entry.copyBytesTo(sectionDataBytes, entrySize, index * entrySize);
|
||||
}
|
||||
String fullSecName;
|
||||
// If relocDat is non-null create section
|
||||
if (sectionDataBytes.length > 0) {
|
||||
int scnType;
|
||||
Elf_Type dataType;
|
||||
if (JNIELFTargetInfo.createReloca() == 0) {
|
||||
scnType = ELF.SHT_REL;
|
||||
dataType = Elf_Type.ELF_T_REL;
|
||||
fullSecName = ".rel" + secName;
|
||||
} else {
|
||||
scnType = ELF.SHT_RELA;
|
||||
dataType = Elf_Type.ELF_T_RELA;
|
||||
fullSecName = ".rela" + secName;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (elfRelocTable.getNumRelocs(i) > 0) {
|
||||
ElfSection sect = sections.get(i);
|
||||
String relname = ".rela" + sect.getName();
|
||||
ElfSection relocSection = createByteSection(sections,
|
||||
relname,
|
||||
elfRelocTable.getRelocData(i),
|
||||
false,
|
||||
0,
|
||||
Elf64_Shdr.SHT_RELA);
|
||||
relocSection.setLink(symtabsectidx);
|
||||
relocSection.setInfo(sect.getSectionId());
|
||||
}
|
||||
// assert compareBytes(relocData.toByteArray(), sectionDataBytes) : "******* Bad array
|
||||
// copy";
|
||||
// sh_link holds the index of section header of symbol table associated with this
|
||||
// relocation table.
|
||||
// sh_info holds the index of section header to which this relocation table applies
|
||||
// to.
|
||||
elfContainer.createSection(fullSecName, sectionDataBytes, dataType, 8, scnType, ELF.SHF_ALLOC, symtab.getSectionId(), container.getSectionId());
|
||||
}
|
||||
}
|
||||
|
||||
private static class SymTabELFContainer implements ELFContainer {
|
||||
private final int symTabSectionIndex;
|
||||
|
||||
public SymTabELFContainer(int symTabSectionIndex) {
|
||||
this.symTabSectionIndex = symTabSectionIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContainerName() {
|
||||
return ".symtab";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionId() {
|
||||
return symTabSectionIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,474 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* File Layout generated by JMachORelocObject
|
||||
*
|
||||
* MachO Header
|
||||
* Load Commands
|
||||
* LC_SEGMENT_64
|
||||
* - Sections
|
||||
* LC_VERSION_MIN_MAX
|
||||
* LC_SYMTAB
|
||||
* LC_DYSYMTAB
|
||||
* Section Data
|
||||
* Relocation entries
|
||||
* Symbol table
|
||||
*
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.macho;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.tools.jaotc.binformat.BinaryContainer;
|
||||
import jdk.tools.jaotc.binformat.ByteContainer;
|
||||
import jdk.tools.jaotc.binformat.CodeContainer;
|
||||
import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
|
||||
import jdk.tools.jaotc.binformat.Relocation;
|
||||
import jdk.tools.jaotc.binformat.Relocation.RelocType;
|
||||
import jdk.tools.jaotc.binformat.Symbol;
|
||||
import jdk.tools.jaotc.binformat.NativeSymbol;
|
||||
import jdk.tools.jaotc.binformat.Symbol.Binding;
|
||||
import jdk.tools.jaotc.binformat.Symbol.Kind;
|
||||
|
||||
import jdk.tools.jaotc.binformat.macho.MachO;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.section_64;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.segment_command_64;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.version_min_command;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.symtab_command;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.dysymtab_command;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.nlist_64;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.reloc_info;
|
||||
import jdk.tools.jaotc.binformat.macho.MachOContainer;
|
||||
import jdk.tools.jaotc.binformat.macho.MachOTargetInfo;
|
||||
import jdk.tools.jaotc.binformat.macho.MachOSymtab;
|
||||
import jdk.tools.jaotc.binformat.macho.MachORelocTable;
|
||||
|
||||
public class JMachORelocObject {
|
||||
|
||||
private final BinaryContainer binContainer;
|
||||
|
||||
private final MachOContainer machoContainer;
|
||||
|
||||
private final int segmentSize;
|
||||
|
||||
public JMachORelocObject(BinaryContainer binContainer, String outputFileName) {
|
||||
this.binContainer = binContainer;
|
||||
this.machoContainer = new MachOContainer(outputFileName);
|
||||
this.segmentSize = binContainer.getCodeSegmentSize();
|
||||
}
|
||||
|
||||
private void createByteSection(ArrayList<MachOSection>sections,
|
||||
ByteContainer c, String sectName, String segName, int scnFlags) {
|
||||
|
||||
if (c.getByteArray().length == 0) {
|
||||
// System.out.println("Skipping creation of " + sectName + " section, no data\n");
|
||||
}
|
||||
|
||||
MachOSection sect = new MachOSection(sectName,
|
||||
segName,
|
||||
c.getByteArray(),
|
||||
scnFlags,
|
||||
c.hasRelocations());
|
||||
// Add this section to our list
|
||||
sections.add(sect);
|
||||
|
||||
// Record the section Id (0 relative)
|
||||
c.setSectionId(sections.size()-1);
|
||||
|
||||
// TODO: Clear out code section data to allow for GC
|
||||
// c.clear();
|
||||
}
|
||||
|
||||
private void createCodeSection(ArrayList<MachOSection>sections, CodeContainer c) {
|
||||
createByteSection(sections, c, /*c.getContainerName()*/ "__text", "__TEXT",
|
||||
section_64.S_ATTR_PURE_INSTRUCTIONS|
|
||||
section_64.S_ATTR_SOME_INSTRUCTIONS);
|
||||
}
|
||||
|
||||
private void createReadOnlySection(ArrayList<MachOSection>sections, ReadOnlyDataContainer c) {
|
||||
createByteSection(sections, c, c.getContainerName(), "__TEXT",
|
||||
section_64.S_ATTR_SOME_INSTRUCTIONS);
|
||||
}
|
||||
|
||||
private void createReadWriteSection(ArrayList<MachOSection>sections, ByteContainer c) {
|
||||
createByteSection(sections, c, c.getContainerName(), "__DATA", section_64.S_REGULAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an MachO relocatable object
|
||||
*
|
||||
* @param relocationTable
|
||||
* @param symbols
|
||||
* @throws IOException throws {@code IOException} as a result of file system access failures.
|
||||
*/
|
||||
public void createMachORelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException {
|
||||
// Allocate MachO Header
|
||||
// with 4 load commands
|
||||
// LC_SEGMENT_64
|
||||
// LC_VERSION_MIN_MACOSX
|
||||
// LC_SYMTAB
|
||||
// LC_DYSYMTAB
|
||||
|
||||
MachOHeader mh = new MachOHeader();
|
||||
|
||||
ArrayList<MachOSection> sections = new ArrayList<MachOSection>();
|
||||
|
||||
// Create Sections contained in the main Segment LC_SEGMENT_64
|
||||
|
||||
createCodeSection(sections, binContainer.getCodeContainer());
|
||||
createReadOnlySection(sections, binContainer.getMetaspaceNamesContainer());
|
||||
createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer());
|
||||
createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer());
|
||||
createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer());
|
||||
createReadWriteSection(sections, binContainer.getMetaspaceGotContainer());
|
||||
createReadWriteSection(sections, binContainer.getMetadataGotContainer());
|
||||
createReadWriteSection(sections, binContainer.getMethodStateContainer());
|
||||
createReadWriteSection(sections, binContainer.getOopGotContainer());
|
||||
createReadWriteSection(sections, binContainer.getMethodMetadataContainer());
|
||||
createReadOnlySection(sections, binContainer.getStubsOffsetsContainer());
|
||||
createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer());
|
||||
createReadOnlySection(sections, binContainer.getCodeSegmentsContainer());
|
||||
createReadOnlySection(sections, binContainer.getConstantDataContainer());
|
||||
createReadOnlySection(sections, binContainer.getConfigContainer());
|
||||
|
||||
// createExternalLinkage();
|
||||
|
||||
createCodeSection(sections, binContainer.getExtLinkageContainer());
|
||||
createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer());
|
||||
// Update the Header sizeofcmds size.
|
||||
// This doesn't include the Header struct size
|
||||
mh.setCmdSizes(4, segment_command_64.totalsize +
|
||||
(section_64.totalsize * sections.size()) +
|
||||
version_min_command.totalsize +
|
||||
symtab_command.totalsize +
|
||||
dysymtab_command.totalsize);
|
||||
|
||||
// Initialize file offset for data past commands
|
||||
int file_offset = mach_header_64.totalsize + mh.getCmdSize();
|
||||
// and round it up
|
||||
file_offset = (file_offset + (sections.get(0).getAlign()-1)) & ~((sections.get(0).getAlign()-1));
|
||||
long address = 0;
|
||||
int segment_offset = file_offset;
|
||||
|
||||
for (int i = 0; i < sections.size(); i++) {
|
||||
MachOSection sect = sections.get(i);
|
||||
file_offset = (file_offset + (sect.getAlign()-1)) & ~((sect.getAlign()-1));
|
||||
address = (address + (sect.getAlign()-1)) & ~((sect.getAlign()-1));
|
||||
sect.setOffset(file_offset);
|
||||
sect.setAddr(address);
|
||||
file_offset += sect.getSize();
|
||||
address += sect.getSize();
|
||||
}
|
||||
|
||||
// File size for Segment data
|
||||
int segment_size = file_offset - segment_offset;
|
||||
|
||||
// Create the LC_SEGMENT_64 Segment which contains the MachOSections
|
||||
MachOSegment seg = new MachOSegment(segment_command_64.totalsize +
|
||||
(section_64.totalsize * sections.size()),
|
||||
segment_offset,
|
||||
segment_size,
|
||||
sections.size());
|
||||
|
||||
|
||||
MachOVersion vers = new MachOVersion();
|
||||
|
||||
// Get symbol data from BinaryContainer object's symbol tables
|
||||
MachOSymtab symtab = createMachOSymbolTables(sections, symbols);
|
||||
|
||||
// Create LC_DYSYMTAB command
|
||||
MachODySymtab dysymtab = new MachODySymtab(symtab.getNumLocalSyms(),
|
||||
symtab.getNumGlobalSyms(),
|
||||
symtab.getNumUndefSyms());
|
||||
|
||||
// Create the Relocation Tables
|
||||
MachORelocTable machORelocs = createMachORelocTable(sections, relocationTable, symtab);
|
||||
// Calculate file offset for relocation data
|
||||
file_offset = (file_offset + (machORelocs.getAlign()-1)) & ~((machORelocs.getAlign()-1));
|
||||
|
||||
// Update relocation sizing information in each section
|
||||
for (int i = 0; i < sections.size(); i++) {
|
||||
MachOSection sect = sections.get(i);
|
||||
if (sect.hasRelocations()) {
|
||||
int nreloc = machORelocs.getNumRelocs(i);
|
||||
sect.setReloff(file_offset);
|
||||
sect.setRelcount(nreloc);
|
||||
file_offset += (nreloc * reloc_info.totalsize);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate and set file offset for symbol table data
|
||||
file_offset = (file_offset + (symtab.getAlign()-1)) & ~((symtab.getAlign()-1));
|
||||
symtab.setOffset(file_offset);
|
||||
|
||||
|
||||
// Write Out Header
|
||||
machoContainer.writeBytes(mh.getArray());
|
||||
// Write out first Segment
|
||||
machoContainer.writeBytes(seg.getArray());
|
||||
// Write out sections within first Segment
|
||||
for (int i = 0; i < sections.size(); i++) {
|
||||
MachOSection sect = sections.get(i);
|
||||
machoContainer.writeBytes(sect.getArray());
|
||||
}
|
||||
|
||||
// Write out LC_VERSION_MIN_MACOSX command
|
||||
machoContainer.writeBytes(vers.getArray());
|
||||
|
||||
// Write out LC_SYMTAB command
|
||||
symtab.calcSizes();
|
||||
machoContainer.writeBytes(symtab.getCmdArray());
|
||||
|
||||
// Write out LC_DYSYMTAB command
|
||||
machoContainer.writeBytes(dysymtab.getArray());
|
||||
|
||||
// Write out data associated with each Section
|
||||
for (int i = 0; i < sections.size(); i++) {
|
||||
MachOSection sect = sections.get(i);
|
||||
machoContainer.writeBytes(sect.getDataArray(), sect.getAlign());
|
||||
}
|
||||
|
||||
// Write out the relocation tables for all sections
|
||||
for (int i = 0; i < sections.size(); i++) {
|
||||
if (machORelocs.getNumRelocs(i) > 0)
|
||||
machoContainer.writeBytes(machORelocs.getRelocData(i), machORelocs.getAlign());
|
||||
}
|
||||
|
||||
// Write out data associated with LC_SYMTAB
|
||||
machoContainer.writeBytes(symtab.getDataArray(), symtab.getAlign());
|
||||
|
||||
machoContainer.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct MachO symbol data from BinaryContainer object's symbol tables. Both dynamic MachO
|
||||
* symbol table and MachO symbol table are created from BinaryContainer's symbol info.
|
||||
*
|
||||
* @param symbols
|
||||
* @param symtab
|
||||
*/
|
||||
private MachOSymtab createMachOSymbolTables(ArrayList<MachOSection>sections,
|
||||
Collection<Symbol> symbols) {
|
||||
MachOSymtab symtab = new MachOSymtab();
|
||||
// First, create the initial null symbol. This is a local symbol.
|
||||
symtab.addSymbolEntry("", (byte)nlist_64.N_UNDF, (byte)0, (long)0);
|
||||
|
||||
// Now create MachO symbol entries for all symbols.
|
||||
for (Symbol symbol : symbols) {
|
||||
int sectionId = symbol.getSection().getSectionId();
|
||||
|
||||
// Symbol offsets are relative to the section memory addr
|
||||
long sectionAddr = sections.get(sectionId).getAddr();
|
||||
|
||||
MachOSymbol machoSymbol = symtab.addSymbolEntry(symbol.getName(),
|
||||
getMachOTypeOf(symbol),
|
||||
(byte)sectionId,
|
||||
symbol.getOffset() + sectionAddr);
|
||||
symbol.setNativeSymbol((NativeSymbol)machoSymbol);
|
||||
}
|
||||
|
||||
// Now that all symbols are enterred, update the
|
||||
// symbol indexes. This is necessary since they will
|
||||
// be reordered based on local, global and undefined.
|
||||
symtab.updateIndexes();
|
||||
|
||||
return (symtab);
|
||||
}
|
||||
|
||||
private static byte getMachOTypeOf(Symbol sym) {
|
||||
Kind kind = sym.getKind();
|
||||
byte type = nlist_64.N_UNDF;
|
||||
|
||||
// Global or Local
|
||||
if (sym.getBinding() == Symbol.Binding.GLOBAL)
|
||||
type = nlist_64.N_EXT;
|
||||
|
||||
// If Function or Data, add section type
|
||||
if (kind == Symbol.Kind.NATIVE_FUNCTION ||
|
||||
kind == Symbol.Kind.JAVA_FUNCTION ||
|
||||
kind == Symbol.Kind.OBJECT) {
|
||||
type |= (nlist_64.N_SECT);
|
||||
}
|
||||
|
||||
return (type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a MachO relocation table from BinaryContainer object's relocation tables.
|
||||
*
|
||||
* @param sections
|
||||
* @param relocationTable
|
||||
* @param symtab
|
||||
*/
|
||||
private MachORelocTable createMachORelocTable(ArrayList<MachOSection> sections,
|
||||
Map<Symbol, List<Relocation>> relocationTable,
|
||||
MachOSymtab symtab) {
|
||||
|
||||
MachORelocTable machORelocTable = new MachORelocTable(sections.size());
|
||||
/*
|
||||
* For each of the symbols with associated relocation records, create a MachO relocation
|
||||
* entry.
|
||||
*/
|
||||
for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) {
|
||||
List<Relocation> relocs = entry.getValue();
|
||||
Symbol symbol = entry.getKey();
|
||||
|
||||
for (Relocation reloc : relocs) {
|
||||
createRelocation(symbol, reloc, machORelocTable);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) {
|
||||
createRelocation(entry.getKey(), entry.getValue(), machORelocTable);
|
||||
}
|
||||
|
||||
return (machORelocTable);
|
||||
}
|
||||
|
||||
private void createRelocation(Symbol symbol, Relocation reloc, MachORelocTable machORelocTable) {
|
||||
RelocType relocType = reloc.getType();
|
||||
|
||||
int machORelocType = getMachORelocationType(relocType);
|
||||
MachOSymbol sym = (MachOSymbol)symbol.getNativeSymbol();
|
||||
int symno = sym.getIndex();
|
||||
int sectindex = reloc.getSection().getSectionId();
|
||||
int offset = reloc.getOffset();
|
||||
int pcrel = 0;
|
||||
int length = 0;
|
||||
int isextern = 1;
|
||||
|
||||
/*
|
||||
System.out.println("reloctype: " + relocType + " size is " +
|
||||
reloc.getSize() + " offset is " + offset +
|
||||
" Section Index is " + (sectindex) +
|
||||
" Symbol Index is " + symno +
|
||||
" Symbol Name is " + symbol.getName() + "\n");
|
||||
*/
|
||||
|
||||
switch (relocType) {
|
||||
case FOREIGN_CALL_DIRECT:
|
||||
case JAVA_CALL_DIRECT:
|
||||
case STUB_CALL_DIRECT:
|
||||
case FOREIGN_CALL_INDIRECT_GOT: {
|
||||
// Create relocation entry
|
||||
// System.out.println("getMachORelocationType: PLT relocation type using X86_64_RELOC_BRANCH");
|
||||
int addend = -4; // Size in bytes of the patch location
|
||||
// Relocation should be applied at the location after call operand
|
||||
offset = offset + reloc.getSize() + addend;
|
||||
pcrel = 1; length = 2;
|
||||
break;
|
||||
}
|
||||
case FOREIGN_CALL_DIRECT_FAR: {
|
||||
// Create relocation entry
|
||||
int addend = -8; // Size in bytes of the patch location
|
||||
// Relocation should be applied at the location after call operand
|
||||
// 10 = 2 (jmp [r]) + 8 (imm64)
|
||||
offset = offset + reloc.getSize() + addend - 2;
|
||||
pcrel = 0; length = 3;
|
||||
break;
|
||||
}
|
||||
case FOREIGN_CALL_INDIRECT:
|
||||
case JAVA_CALL_INDIRECT:
|
||||
case STUB_CALL_INDIRECT: {
|
||||
// Do nothing.
|
||||
return;
|
||||
}
|
||||
case EXTERNAL_DATA_REFERENCE_FAR: {
|
||||
// Create relocation entry
|
||||
int addend = -4; // Size of 32-bit address of the GOT
|
||||
/*
|
||||
* Relocation should be applied before the test instruction to the move instruction.
|
||||
* offset points to the test instruction after the instruction that loads
|
||||
* the address of polling page. So set the offset appropriately.
|
||||
*/
|
||||
offset = offset + addend;
|
||||
pcrel = 0; length = 2;
|
||||
break;
|
||||
}
|
||||
case METASPACE_GOT_REFERENCE:
|
||||
case EXTERNAL_PLT_TO_GOT:
|
||||
case STATIC_STUB_TO_STATIC_METHOD:
|
||||
case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: {
|
||||
int addend = -4; // Size of 32-bit address of the GOT
|
||||
/*
|
||||
* Relocation should be applied before the test instruction to
|
||||
* the move instruction. reloc.getOffset() points to the
|
||||
* test instruction after the instruction that loads the
|
||||
* address of polling page. So set the offset appropriately.
|
||||
*/
|
||||
offset = offset + addend;
|
||||
pcrel = 1; length = 2;
|
||||
break;
|
||||
}
|
||||
case EXTERNAL_GOT_TO_PLT:
|
||||
case LOADTIME_ADDRESS: {
|
||||
// this is load time relocations
|
||||
pcrel = 0; length = 3;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new InternalError("Unhandled relocation type: " + relocType);
|
||||
}
|
||||
machORelocTable.createRelocationEntry(sectindex, offset, symno,
|
||||
pcrel, length, isextern,
|
||||
machORelocType);
|
||||
}
|
||||
|
||||
private static int getMachORelocationType(RelocType relocType) {
|
||||
int machORelocType = 0;
|
||||
switch (MachOTargetInfo.getMachOArch()) {
|
||||
case mach_header_64.CPU_TYPE_X86_64:
|
||||
// Return X86_64_RELOC_* entries based on relocType
|
||||
if (relocType == RelocType.FOREIGN_CALL_DIRECT || relocType == RelocType.JAVA_CALL_DIRECT || relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
|
||||
machORelocType = reloc_info.X86_64_RELOC_BRANCH;
|
||||
} else if (relocType == RelocType.STUB_CALL_DIRECT) {
|
||||
machORelocType = reloc_info.X86_64_RELOC_BRANCH;
|
||||
} else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) {
|
||||
machORelocType = reloc_info.X86_64_RELOC_UNSIGNED;
|
||||
} else if (relocType == RelocType.FOREIGN_CALL_INDIRECT || relocType == RelocType.JAVA_CALL_INDIRECT || relocType == RelocType.STUB_CALL_INDIRECT) {
|
||||
machORelocType = reloc_info.X86_64_RELOC_NONE;
|
||||
} else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) {
|
||||
machORelocType = reloc_info.X86_64_RELOC_GOT;
|
||||
} else if (relocType == RelocType.METASPACE_GOT_REFERENCE || relocType == RelocType.EXTERNAL_PLT_TO_GOT || relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD ||
|
||||
relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) {
|
||||
machORelocType = reloc_info.X86_64_RELOC_BRANCH;
|
||||
} else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT || relocType == RelocType.LOADTIME_ADDRESS) {
|
||||
machORelocType = reloc_info.X86_64_RELOC_UNSIGNED;
|
||||
} else {
|
||||
assert false : "Unhandled relocation type: " + relocType;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
System.out.println("Relocation Type mapping: Unhandled architecture");
|
||||
}
|
||||
return machORelocType;
|
||||
}
|
||||
}
|
@ -0,0 +1,307 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.macho;
|
||||
|
||||
/**
|
||||
*
|
||||
* Support for the creation of Mach-o Object files.
|
||||
* Current support is limited to 64 bit x86_64.
|
||||
*
|
||||
* File Format Overview:
|
||||
*
|
||||
* mach_header
|
||||
* load_commands
|
||||
* Typical Mac OSX 64-bit object files have these 4 load_commands
|
||||
* (LC_SEGMENT_64, LC_SYMTAB, LC_VERSIN_MIN_MACOSX, LC_DYSYMTAB)
|
||||
* Segments corresponding to load_commands
|
||||
* (which each include multiple Sections)
|
||||
*/
|
||||
|
||||
public class MachO {
|
||||
|
||||
/**
|
||||
* mach_header_64 structure defines
|
||||
*/
|
||||
public enum mach_header_64 {
|
||||
magic( 0, 4),
|
||||
cputype( 4, 4),
|
||||
cpusubtype( 8, 4),
|
||||
filetype(12, 4),
|
||||
ncmds(16, 4),
|
||||
sizeofcmds(20, 4),
|
||||
flags(24, 4),
|
||||
reserved(28, 4);
|
||||
|
||||
public final int off;
|
||||
public final int sz;
|
||||
|
||||
mach_header_64(int offset, int size) {
|
||||
this.off = offset;
|
||||
this.sz = size;
|
||||
}
|
||||
|
||||
public static int totalsize = 32;
|
||||
|
||||
/**
|
||||
* mach_header_64 defines
|
||||
*/
|
||||
public static final int MH_MAGIC = 0xfeedface;
|
||||
public static final int MH_MAGIC_64 = 0xfeedfacf;
|
||||
public static final int MH_SUBSECTIONS_VIA_SYMBOLS = 0x2000;
|
||||
|
||||
/**
|
||||
* filetype
|
||||
*/
|
||||
public static final int MH_OBJECT = 0x1;
|
||||
|
||||
/**
|
||||
* cputype
|
||||
*/
|
||||
public static final int CPU_TYPE_ANY = -1;
|
||||
public static final int CPU_ARCH_ABI64 = 0x1000000;
|
||||
public static final int CPU_TYPE_X86_64 = 0x1000007;
|
||||
public static final int CPU_TYPE_ARM64 = 0x100000c;
|
||||
/**
|
||||
* cpusubtype
|
||||
*/
|
||||
public static final int CPU_SUBTYPE_I386_ALL = 3;
|
||||
public static final int CPU_SUBTYPE_ARM64_ALL = 0;
|
||||
public static final int CPU_SUBTYPE_LITTLE_ENDIAN = 0;
|
||||
public static final int CPU_SUBTYPE_BIG_ENDIAN = 1;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* segment_command_64 structure defines
|
||||
*/
|
||||
public enum segment_command_64 {
|
||||
cmd( 0, 4),
|
||||
cmdsize( 4, 4),
|
||||
segname( 8,16),
|
||||
vmaddr(24, 8),
|
||||
vmsize(32, 8),
|
||||
fileoff(40, 8),
|
||||
filesize(48, 8),
|
||||
maxprot(56, 4),
|
||||
initprot(60, 4),
|
||||
nsects(64, 4),
|
||||
flags(68, 4);
|
||||
|
||||
public final int off;
|
||||
public final int sz;
|
||||
|
||||
segment_command_64(int offset, int size) {
|
||||
this.off = offset;
|
||||
this.sz = size;
|
||||
}
|
||||
|
||||
public static int totalsize = 72;
|
||||
|
||||
public static final int LC_SEGMENT_64 = 0x19;
|
||||
}
|
||||
|
||||
/**
|
||||
* section_64 structure defines
|
||||
*/
|
||||
public enum section_64 {
|
||||
sectname( 0,16),
|
||||
segname(16,16),
|
||||
addr(32, 8),
|
||||
size(40, 8),
|
||||
offset(48, 4),
|
||||
align(52, 4),
|
||||
reloff(56, 4),
|
||||
nreloc(60, 4),
|
||||
flags(64, 4),
|
||||
reserved1(68, 4),
|
||||
reserved2(72, 4),
|
||||
reserved3(76, 4);
|
||||
|
||||
public final int off;
|
||||
public final int sz;
|
||||
|
||||
section_64(int offset, int size) {
|
||||
this.off = offset;
|
||||
this.sz = size;
|
||||
}
|
||||
|
||||
public static int totalsize = 80;
|
||||
|
||||
public static int S_REGULAR = 0x0;
|
||||
public static int S_CSTRING_LITERALS = 0x2;
|
||||
public static int S_ATTR_PURE_INSTRUCTIONS = 0x80000000;
|
||||
public static int S_ATTR_SOME_INSTRUCTIONS = 0x400;
|
||||
}
|
||||
|
||||
/**
|
||||
* version_min_command structure defines
|
||||
*/
|
||||
public enum version_min_command {
|
||||
cmd( 0, 4),
|
||||
cmdsize( 4, 4),
|
||||
version( 8, 4),
|
||||
sdk(12, 4);
|
||||
|
||||
public final int off;
|
||||
public final int sz;
|
||||
|
||||
version_min_command(int offset, int size) {
|
||||
this.off = offset;
|
||||
this.sz = size;
|
||||
}
|
||||
|
||||
public static int totalsize = 16;
|
||||
|
||||
public static final int LC_VERSION_MIN_MACOSX = 0x24;
|
||||
public static final int LC_VERSION_MIN_IPHONEOS = 0x25;
|
||||
}
|
||||
|
||||
/**
|
||||
* symtab_command structure defines
|
||||
*/
|
||||
public enum symtab_command {
|
||||
cmd( 0, 4),
|
||||
cmdsize( 4, 4),
|
||||
symoff( 8, 4),
|
||||
nsyms(12, 4),
|
||||
stroff(16, 4),
|
||||
strsize(20, 4);
|
||||
|
||||
public final int off;
|
||||
public final int sz;
|
||||
|
||||
symtab_command(int offset, int size) {
|
||||
this.off = offset;
|
||||
this.sz = size;
|
||||
}
|
||||
|
||||
public static int totalsize = 24;
|
||||
|
||||
public static final int LC_SYMTAB = 0x2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Symbol table entry definitions
|
||||
*
|
||||
* nlist_64 structure defines
|
||||
*/
|
||||
public enum nlist_64 {
|
||||
n_strx( 0, 4),
|
||||
n_type( 4, 1),
|
||||
n_sect( 5, 1),
|
||||
n_desc( 6, 2),
|
||||
n_value( 8, 8);
|
||||
|
||||
public final int off;
|
||||
public final int sz;
|
||||
|
||||
nlist_64(int offset, int size) {
|
||||
this.off = offset;
|
||||
this.sz = size;
|
||||
}
|
||||
|
||||
public static int totalsize = 16;
|
||||
|
||||
public static final int N_EXT = 0x1;
|
||||
public static final int N_TYPE = 0xe;
|
||||
public static final int N_UNDF = 0x0;
|
||||
public static final int N_SECT = 0xe;
|
||||
}
|
||||
|
||||
/**
|
||||
* dysymtab_command structure defines
|
||||
*/
|
||||
public enum dysymtab_command {
|
||||
cmd( 0, 4),
|
||||
cmdsize( 4, 4),
|
||||
ilocalsym( 8, 4),
|
||||
nlocalsym(12, 4),
|
||||
iextdefsym(16, 4),
|
||||
nextdefsym(20, 4),
|
||||
iundefsym(24, 4),
|
||||
nundefsym(28, 4),
|
||||
tocoff(32, 4),
|
||||
ntoc(36, 4),
|
||||
modtaboff(40, 4),
|
||||
nmodtab(44, 4),
|
||||
extrefsymoff(48, 4),
|
||||
nextrefsyms(52, 4),
|
||||
indirectsymoff(56, 4),
|
||||
nindirectsyms(60, 4),
|
||||
extreloff(64, 4),
|
||||
nextrel(68, 4),
|
||||
locreloff(72, 4),
|
||||
nlocrel(76, 4);
|
||||
|
||||
public final int off;
|
||||
public final int sz;
|
||||
|
||||
dysymtab_command(int offset, int size) {
|
||||
this.off = offset;
|
||||
this.sz = size;
|
||||
}
|
||||
|
||||
public static int totalsize = 80;
|
||||
|
||||
public static final int LC_DYSYMTAB = 0xb;
|
||||
}
|
||||
|
||||
/**
|
||||
* relocation_info structure defines
|
||||
*/
|
||||
public enum reloc_info {
|
||||
r_address( 0, 4),
|
||||
r_relocinfo( 4, 4);
|
||||
|
||||
public final int off;
|
||||
public final int sz;
|
||||
|
||||
reloc_info(int offset, int size) {
|
||||
this.off = offset;
|
||||
this.sz = size;
|
||||
}
|
||||
|
||||
public static int totalsize = 8;
|
||||
|
||||
public static final int REL_SYMNUM_MASK = 0xffffff;
|
||||
public static final int REL_SYMNUM_SHIFT = 0x0;
|
||||
public static final int REL_PCREL_MASK = 0x1;
|
||||
public static final int REL_PCREL_SHIFT = 0x18;
|
||||
public static final int REL_LENGTH_MASK = 0x3;
|
||||
public static final int REL_LENGTH_SHIFT = 0x19;
|
||||
public static final int REL_EXTERN_MASK = 0x1;
|
||||
public static final int REL_EXTERN_SHIFT = 0x1b;
|
||||
public static final int REL_TYPE_MASK = 0xf;
|
||||
public static final int REL_TYPE_SHIFT = 0x1c;
|
||||
|
||||
/* reloc_type_x86_64 defines */
|
||||
|
||||
public static final int X86_64_RELOC_NONE = 0x0;
|
||||
public static final int X86_64_RELOC_BRANCH = 0x2;
|
||||
public static final int X86_64_RELOC_GOT = 0x4;
|
||||
public static final int X86_64_RELOC_GOT_LOAD = 0x3;
|
||||
public static final int X86_64_RELOC_SIGNED = 0x1;
|
||||
public static final int X86_64_RELOC_UNSIGNED = 0x0;
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.macho;
|
||||
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import jdk.tools.jaotc.binformat.macho.MachOTargetInfo;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64;
|
||||
|
||||
public class MachOByteBuffer {
|
||||
|
||||
public static ByteBuffer allocate(int size) {
|
||||
ByteBuffer buf = ByteBuffer.allocate(size);
|
||||
if (MachOTargetInfo.getMachOEndian() ==
|
||||
MachO.mach_header_64.CPU_SUBTYPE_LITTLE_ENDIAN)
|
||||
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||
else
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
return (buf);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.macho;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
public class MachOContainer {
|
||||
|
||||
File outputFile;
|
||||
FileOutputStream outputStream;
|
||||
long fileOffset;
|
||||
|
||||
public MachOContainer(String fileName) {
|
||||
String baseName;
|
||||
|
||||
outputFile = new File(fileName);
|
||||
if (outputFile.exists()) {
|
||||
outputFile.delete();
|
||||
}
|
||||
|
||||
try {
|
||||
outputStream = new FileOutputStream(outputFile);
|
||||
} catch (Exception e) {
|
||||
System.out.println("MachOContainer: Can't create file " + fileName);
|
||||
}
|
||||
fileOffset = 0;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
outputStream.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println("MachOContainer: close failed");
|
||||
}
|
||||
}
|
||||
|
||||
public void writeBytes(byte [] bytes) {
|
||||
try {
|
||||
outputStream.write(bytes);
|
||||
} catch (Exception e) {
|
||||
System.out.println("MachOContainer: writeBytes failed");
|
||||
}
|
||||
fileOffset += bytes.length;
|
||||
}
|
||||
|
||||
// Write bytes to output file with up front alignment padding
|
||||
public void writeBytes(byte [] bytes, int alignment) {
|
||||
try {
|
||||
// Pad to alignment
|
||||
while ((fileOffset & (long)(alignment-1)) != 0) {
|
||||
outputStream.write(0);
|
||||
fileOffset++;
|
||||
}
|
||||
outputStream.write(bytes);
|
||||
} catch (Exception e) {
|
||||
System.out.println("MachOContainer: writeBytes failed");
|
||||
}
|
||||
fileOffset += bytes.length;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.macho;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.tools.jaotc.binformat.macho.MachO;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.dysymtab_command;
|
||||
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
|
||||
|
||||
public class MachODySymtab {
|
||||
ByteBuffer dysymtab;
|
||||
|
||||
public MachODySymtab(int nlocal, int nglobal, int nundef) {
|
||||
dysymtab = MachOByteBuffer.allocate(dysymtab_command.totalsize);
|
||||
|
||||
dysymtab.putInt(dysymtab_command.cmd.off, dysymtab_command.LC_DYSYMTAB);
|
||||
dysymtab.putInt(dysymtab_command.cmdsize.off, dysymtab_command.totalsize);
|
||||
dysymtab.putInt(dysymtab_command.ilocalsym.off, 0);
|
||||
dysymtab.putInt(dysymtab_command.nlocalsym.off, nlocal);
|
||||
dysymtab.putInt(dysymtab_command.iextdefsym.off, nlocal);
|
||||
dysymtab.putInt(dysymtab_command.nextdefsym.off, nglobal);
|
||||
dysymtab.putInt(dysymtab_command.iundefsym.off, nlocal+nglobal);
|
||||
dysymtab.putInt(dysymtab_command.nundefsym.off, nundef);
|
||||
}
|
||||
|
||||
public byte[] getArray() {
|
||||
return dysymtab.array();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.macho;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.tools.jaotc.binformat.macho.MachO;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64;
|
||||
import jdk.tools.jaotc.binformat.macho.MachOTargetInfo;
|
||||
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
|
||||
|
||||
public class MachOHeader {
|
||||
ByteBuffer header;
|
||||
|
||||
public MachOHeader() {
|
||||
header = MachOByteBuffer.allocate(mach_header_64.totalsize);
|
||||
|
||||
header.putInt(mach_header_64.magic.off, mach_header_64.MH_MAGIC_64);
|
||||
header.putInt(mach_header_64.cputype.off, MachOTargetInfo.getMachOArch());
|
||||
header.putInt(mach_header_64.cpusubtype.off, MachOTargetInfo.getMachOSubArch());
|
||||
header.putInt(mach_header_64.flags.off, 0x2000);
|
||||
header.putInt(mach_header_64.filetype.off, mach_header_64.MH_OBJECT);
|
||||
}
|
||||
|
||||
public void setCmdSizes(int ncmds, int sizeofcmds) {
|
||||
header.putInt(mach_header_64.ncmds.off, ncmds);
|
||||
header.putInt(mach_header_64.sizeofcmds.off, sizeofcmds);
|
||||
}
|
||||
|
||||
public int getCmdSize() {
|
||||
return (header.getInt(mach_header_64.sizeofcmds.off));
|
||||
}
|
||||
|
||||
public byte[] getArray() {
|
||||
return header.array();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.macho;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.tools.jaotc.binformat.macho.MachO;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.reloc_info;
|
||||
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
|
||||
|
||||
public class MachORelocEntry {
|
||||
ByteBuffer entry;
|
||||
|
||||
public MachORelocEntry(int offset,
|
||||
int symno,
|
||||
int pcrel,
|
||||
int length,
|
||||
int isextern,
|
||||
int type) {
|
||||
|
||||
entry = MachOByteBuffer.allocate(reloc_info.totalsize);
|
||||
|
||||
entry.putInt(reloc_info.r_address.off, offset);
|
||||
|
||||
// Encode and store the relocation entry bitfields
|
||||
entry.putInt(reloc_info.r_relocinfo.off,
|
||||
((symno & reloc_info.REL_SYMNUM_MASK)
|
||||
<< reloc_info.REL_SYMNUM_SHIFT) |
|
||||
((pcrel & reloc_info.REL_PCREL_MASK)
|
||||
<< reloc_info.REL_PCREL_SHIFT) |
|
||||
((length & reloc_info.REL_LENGTH_MASK)
|
||||
<< reloc_info.REL_LENGTH_SHIFT) |
|
||||
((isextern & reloc_info.REL_EXTERN_MASK)
|
||||
<< reloc_info.REL_EXTERN_SHIFT) |
|
||||
((type & reloc_info.REL_TYPE_MASK)
|
||||
<< reloc_info.REL_TYPE_SHIFT));
|
||||
}
|
||||
|
||||
public byte[] getArray() {
|
||||
return entry.array();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.macho;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.tools.jaotc.binformat.macho.MachORelocEntry;
|
||||
import jdk.tools.jaotc.binformat.macho.MachOTargetInfo;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.reloc_info;
|
||||
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
|
||||
|
||||
public class MachORelocTable {
|
||||
ArrayList<ArrayList<MachORelocEntry>> relocEntries;
|
||||
int fileOffset;
|
||||
|
||||
public MachORelocTable(int numsects) {
|
||||
relocEntries = new ArrayList<ArrayList<MachORelocEntry>>(numsects);
|
||||
for (int i = 0; i < numsects; i++)
|
||||
relocEntries.add(new ArrayList<MachORelocEntry>());
|
||||
}
|
||||
|
||||
public void createRelocationEntry(int sectindex,
|
||||
int offset,
|
||||
int symno,
|
||||
int pcrel,
|
||||
int length,
|
||||
int isextern,
|
||||
int type) {
|
||||
|
||||
MachORelocEntry entry = new MachORelocEntry(offset,
|
||||
symno,
|
||||
pcrel,
|
||||
length,
|
||||
isextern,
|
||||
type);
|
||||
relocEntries.get(sectindex).add(entry);
|
||||
}
|
||||
|
||||
public int getAlign() {
|
||||
return (4);
|
||||
}
|
||||
|
||||
public int getNumRelocs(int section_index) {
|
||||
return relocEntries.get(section_index).size();
|
||||
}
|
||||
|
||||
// Return the relocation entries for a single section
|
||||
// or null if no entries added to section
|
||||
public byte [] getRelocData(int section_index) {
|
||||
ArrayList<MachORelocEntry> entryList = relocEntries.get(section_index);
|
||||
|
||||
if (entryList.size() == 0)
|
||||
return null;
|
||||
|
||||
ByteBuffer relocData = MachOByteBuffer.allocate(entryList.size() * reloc_info.totalsize);
|
||||
|
||||
// Copy each entry to a single ByteBuffer
|
||||
for (int i = 0; i < entryList.size(); i++) {
|
||||
MachORelocEntry entry = entryList.get(i);
|
||||
relocData.put(entry.getArray());
|
||||
}
|
||||
|
||||
return (relocData.array());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.macho;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.tools.jaotc.binformat.macho.MachO;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.section_64;
|
||||
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
|
||||
|
||||
public class MachOSection {
|
||||
ByteBuffer section;
|
||||
byte [] data;
|
||||
boolean hasrelocations;
|
||||
|
||||
public MachOSection(String sectName, String segName, byte [] sectData, int sectFlags, boolean hasRelocations) {
|
||||
section = MachOByteBuffer.allocate(section_64.totalsize);
|
||||
|
||||
// TODO: Hotspot uses long section names.
|
||||
// They are getting truncated.
|
||||
// Is this a problem??
|
||||
byte[] sectNameBytes = sectName.getBytes();
|
||||
int sectNameMax = section_64.sectname.sz < sectNameBytes.length ?
|
||||
section_64.sectname.sz : sectNameBytes.length;
|
||||
|
||||
for (int i = 0; i < sectNameMax; i++)
|
||||
section.put(section_64.sectname.off+i, sectNameBytes[i]);
|
||||
|
||||
byte[] segNameBytes = segName.getBytes();
|
||||
int segNameMax = section_64.segname.sz < segNameBytes.length ?
|
||||
section_64.segname.sz : segNameBytes.length;
|
||||
|
||||
for (int i = 0; i < segNameMax; i++)
|
||||
section.put(section_64.segname.off+i, segNameBytes[i]);
|
||||
|
||||
section.putLong(section_64.size.off, sectData.length);
|
||||
|
||||
// For now use 8 byte alignment
|
||||
section.putInt(section_64.align.off, 3);
|
||||
|
||||
section.putInt(section_64.flags.off, sectFlags);
|
||||
|
||||
data = sectData;
|
||||
|
||||
hasrelocations = hasRelocations;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return section.getLong(section_64.size.off);
|
||||
}
|
||||
|
||||
public int getAlign() {
|
||||
return (1 << section.getInt(section_64.align.off));
|
||||
}
|
||||
|
||||
public byte[] getArray() {
|
||||
return section.array();
|
||||
}
|
||||
|
||||
public byte[] getDataArray() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setAddr(long addr) {
|
||||
section.putLong(section_64.addr.off, addr);
|
||||
}
|
||||
|
||||
public long getAddr() {
|
||||
return (section.getLong(section_64.addr.off));
|
||||
}
|
||||
|
||||
public void setOffset(int offset) {
|
||||
section.putInt(section_64.offset.off, offset);
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return (section.getInt(section_64.offset.off));
|
||||
}
|
||||
|
||||
public void setReloff(int offset) {
|
||||
section.putInt(section_64.reloff.off, offset);
|
||||
}
|
||||
|
||||
public void setRelcount(int count) {
|
||||
section.putInt(section_64.nreloc.off, count);
|
||||
}
|
||||
|
||||
public boolean hasRelocations() {
|
||||
return hasrelocations;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.macho;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.tools.jaotc.binformat.macho.MachO;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.segment_command_64;
|
||||
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
|
||||
|
||||
public class MachOSegment {
|
||||
ByteBuffer segment;
|
||||
|
||||
public MachOSegment(int size, int fileoff, int filesize, int nsects) {
|
||||
segment = MachOByteBuffer.allocate(segment_command_64.totalsize);
|
||||
|
||||
segment.putInt(segment_command_64.cmd.off, segment_command_64.LC_SEGMENT_64);
|
||||
segment.putInt(segment_command_64.cmdsize.off, size);
|
||||
segment.putInt(segment_command_64.maxprot.off, 7);
|
||||
segment.putInt(segment_command_64.initprot.off, 7);
|
||||
segment.putInt(segment_command_64.nsects.off, nsects);
|
||||
segment.putInt(segment_command_64.flags.off, 0);
|
||||
segment.putLong(segment_command_64.vmaddr.off, 0);
|
||||
segment.putLong(segment_command_64.vmsize.off, filesize);
|
||||
segment.putLong(segment_command_64.fileoff.off, fileoff);
|
||||
segment.putLong(segment_command_64.filesize.off, filesize);
|
||||
}
|
||||
|
||||
public byte[] getArray() {
|
||||
return segment.array();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.macho;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.tools.jaotc.binformat.NativeSymbol;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.nlist_64;
|
||||
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
|
||||
|
||||
public class MachOSymbol extends NativeSymbol {
|
||||
ByteBuffer sym;
|
||||
|
||||
public MachOSymbol(int symbolindex, int strindex, byte type, byte sectindex, long offset) {
|
||||
super(symbolindex);
|
||||
sym = MachOByteBuffer.allocate(nlist_64.totalsize);
|
||||
|
||||
sym.putInt(nlist_64.n_strx.off, strindex);
|
||||
sym.put(nlist_64.n_type.off, type);
|
||||
// Section indexes start at 1 but we manage the index internally
|
||||
// as 0 relative
|
||||
sym.put(nlist_64.n_sect.off, (byte)(sectindex+1));
|
||||
sym.putChar(nlist_64.n_desc.off, (char )0);
|
||||
sym.putLong(nlist_64.n_value.off, offset);
|
||||
}
|
||||
|
||||
public byte[] getArray() {
|
||||
return sym.array();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.macho;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import jdk.tools.jaotc.binformat.macho.MachO;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.symtab_command;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.nlist_64;
|
||||
import jdk.tools.jaotc.binformat.macho.MachOSymbol;
|
||||
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
|
||||
|
||||
public class MachOSymtab {
|
||||
|
||||
/**
|
||||
* ByteBuffer holding the LC_SYMTAB command contents
|
||||
*/
|
||||
ByteBuffer symtabCmd;
|
||||
|
||||
/**
|
||||
* ByteBuffer holding the symbol table entries and strings
|
||||
*/
|
||||
ByteBuffer symtabData;
|
||||
|
||||
int symtabDataSize;
|
||||
|
||||
ArrayList<MachOSymbol>localSymbols = new ArrayList<MachOSymbol>();
|
||||
ArrayList<MachOSymbol>globalSymbols = new ArrayList<MachOSymbol>();
|
||||
ArrayList<MachOSymbol>undefSymbols = new ArrayList<MachOSymbol>();
|
||||
|
||||
/**
|
||||
* number of symbols added
|
||||
*/
|
||||
int symbolCount;
|
||||
|
||||
/**
|
||||
* String holding symbol table strings
|
||||
*/
|
||||
private StringBuilder strTabContent = new StringBuilder();
|
||||
|
||||
/**
|
||||
* Keeps track of bytes in string table since strTabContent.length()
|
||||
* is number of chars, not bytes.
|
||||
*/
|
||||
private int strTabNrOfBytes = 0;
|
||||
|
||||
public MachOSymtab() {
|
||||
symtabCmd = MachOByteBuffer.allocate(symtab_command.totalsize);
|
||||
|
||||
symtabCmd.putInt(symtab_command.cmd.off, symtab_command.LC_SYMTAB);
|
||||
symtabCmd.putInt(symtab_command.cmdsize.off, symtab_command.totalsize);
|
||||
|
||||
symbolCount = 0;
|
||||
|
||||
}
|
||||
|
||||
public int getAlign() {
|
||||
return (4);
|
||||
}
|
||||
|
||||
public MachOSymbol addSymbolEntry(String name, byte type, byte secHdrIndex, long offset) {
|
||||
// Get the current symbol index and append symbol name to string table.
|
||||
int index;
|
||||
MachOSymbol sym;
|
||||
|
||||
if (name.isEmpty()) {
|
||||
index = 0;
|
||||
strTabContent.append('\0');
|
||||
strTabNrOfBytes += 1;
|
||||
sym = new MachOSymbol(symbolCount, index, type, secHdrIndex, offset);
|
||||
localSymbols.add(sym);
|
||||
} else {
|
||||
// We can't trust strTabContent.length() since that is
|
||||
// chars (UTF16), keep track of bytes on our own.
|
||||
index = strTabNrOfBytes;
|
||||
strTabContent.append("_").append(name).append('\0');
|
||||
// + 1 for null, + 1 for "_"
|
||||
strTabNrOfBytes += (name.getBytes().length + 1 + 1);
|
||||
|
||||
sym = new MachOSymbol(symbolCount, index, type, secHdrIndex, offset);
|
||||
switch (type) {
|
||||
case nlist_64.N_EXT:
|
||||
undefSymbols.add(sym);
|
||||
break;
|
||||
case nlist_64.N_SECT:
|
||||
case nlist_64.N_UNDF: // null symbol
|
||||
localSymbols.add(sym);
|
||||
break;
|
||||
case nlist_64.N_SECT|nlist_64.N_EXT:
|
||||
globalSymbols.add(sym);
|
||||
break;
|
||||
default:
|
||||
System.out.println("Unsupported Symbol type " + type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
symbolCount++;
|
||||
return (sym);
|
||||
}
|
||||
|
||||
public void setOffset(int symoff) {
|
||||
symtabCmd.putInt(symtab_command.symoff.off, symoff);
|
||||
}
|
||||
|
||||
// Update the symbol indexes once all symbols have been added.
|
||||
// This is required since we'll be reordering the symbols in the
|
||||
// file to be in the order of Local, global and Undefined.
|
||||
public void updateIndexes() {
|
||||
int index = 0;
|
||||
|
||||
// Update the local symbol indexes
|
||||
for (int i = 0; i < localSymbols.size(); i++ ) {
|
||||
MachOSymbol sym = localSymbols.get(i);
|
||||
sym.setIndex(index++);
|
||||
}
|
||||
|
||||
// Update the global symbol indexes
|
||||
for (int i = 0; i < globalSymbols.size(); i++ ) {
|
||||
MachOSymbol sym = globalSymbols.get(i);
|
||||
sym.setIndex(index++);
|
||||
}
|
||||
|
||||
// Update the undefined symbol indexes
|
||||
for (int i = index; i < undefSymbols.size(); i++ ) {
|
||||
MachOSymbol sym = undefSymbols.get(i);
|
||||
sym.setIndex(index++);
|
||||
}
|
||||
}
|
||||
|
||||
// Update LC_SYMTAB command fields based on the number of symbols added
|
||||
// return the file size taken up by symbol table entries and strings
|
||||
public int calcSizes() {
|
||||
int stroff;
|
||||
|
||||
stroff = symtabCmd.getInt(symtab_command.symoff.off) + (nlist_64.totalsize * symbolCount);
|
||||
symtabCmd.putInt(symtab_command.nsyms.off, symbolCount);
|
||||
symtabCmd.putInt(symtab_command.stroff.off, stroff);
|
||||
symtabCmd.putInt(symtab_command.strsize.off, strTabNrOfBytes);
|
||||
symtabDataSize = (nlist_64.totalsize * symbolCount) + strTabNrOfBytes;
|
||||
|
||||
return (symtabDataSize);
|
||||
}
|
||||
|
||||
public int getNumLocalSyms() { return localSymbols.size(); }
|
||||
public int getNumGlobalSyms() { return globalSymbols.size(); }
|
||||
public int getNumUndefSyms() { return undefSymbols.size(); }
|
||||
|
||||
public byte[] getCmdArray() {
|
||||
return symtabCmd.array();
|
||||
}
|
||||
|
||||
// Create a single byte array that contains the symbol table entries
|
||||
// and string table
|
||||
public byte[] getDataArray() {
|
||||
int index = 0;
|
||||
symtabData = MachOByteBuffer.allocate(symtabDataSize);
|
||||
byte [] retarray;
|
||||
|
||||
// Add the local symbols
|
||||
for (int i = 0; i < localSymbols.size(); i++ ) {
|
||||
MachOSymbol sym = localSymbols.get(i);
|
||||
byte [] arr = sym.getArray();
|
||||
symtabData.put(arr);
|
||||
}
|
||||
// Add the global symbols
|
||||
for (int i = 0; i < globalSymbols.size(); i++ ) {
|
||||
MachOSymbol sym = globalSymbols.get(i);
|
||||
byte [] arr = sym.getArray();
|
||||
symtabData.put(arr);
|
||||
}
|
||||
// Add the undefined symbols
|
||||
for (int i = 0; i < undefSymbols.size(); i++ ) {
|
||||
MachOSymbol sym = undefSymbols.get(i);
|
||||
byte [] arr = sym.getArray();
|
||||
symtabData.put(arr);
|
||||
}
|
||||
|
||||
// Add the stringtable
|
||||
byte [] strs = strTabContent.toString().getBytes();
|
||||
symtabData.put(strs);
|
||||
|
||||
retarray = symtabData.array();
|
||||
|
||||
return (retarray);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.macho;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64;
|
||||
|
||||
/**
|
||||
* Class that abstracts MACH-O target details.
|
||||
*
|
||||
*/
|
||||
public class MachOTargetInfo {
|
||||
/**
|
||||
* Target architecture and subtype.
|
||||
*/
|
||||
private static final int arch;
|
||||
private static final int subarch;
|
||||
|
||||
/**
|
||||
* Architecture endian-ness.
|
||||
*/
|
||||
private static final int endian = mach_header_64.CPU_SUBTYPE_LITTLE_ENDIAN;
|
||||
|
||||
/**
|
||||
* Target OS string.
|
||||
*/
|
||||
private static final String osName;
|
||||
|
||||
static {
|
||||
// Find the target arch details
|
||||
String archStr = System.getProperty("os.arch").toLowerCase();
|
||||
|
||||
if (ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN) {
|
||||
System.out.println("Only Little Endian byte order supported!");
|
||||
}
|
||||
|
||||
if (archStr.equals("amd64") || archStr.equals("x86_64")) {
|
||||
arch = mach_header_64.CPU_TYPE_X86_64;
|
||||
subarch = mach_header_64.CPU_SUBTYPE_I386_ALL;
|
||||
} else {
|
||||
System.out.println("Unsupported architecture " + archStr);
|
||||
arch = mach_header_64.CPU_TYPE_ANY;
|
||||
subarch = 0;
|
||||
}
|
||||
|
||||
osName = System.getProperty("os.name").toLowerCase();
|
||||
}
|
||||
|
||||
public static int getMachOArch() {
|
||||
return arch;
|
||||
}
|
||||
|
||||
public static int getMachOSubArch() {
|
||||
return subarch;
|
||||
}
|
||||
|
||||
public static int getMachOEndian() {
|
||||
return endian;
|
||||
}
|
||||
|
||||
public static String getOsName() {
|
||||
return osName;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -20,36 +20,30 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.api.collections;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
package jdk.tools.jaotc.binformat.macho;
|
||||
|
||||
/**
|
||||
* A default implementation of {@link CollectionsProvider} that creates standard JDK collection
|
||||
* class objects.
|
||||
*/
|
||||
public class DefaultCollectionsProvider implements CollectionsProvider {
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
@Override
|
||||
public <E> Set<E> newIdentitySet() {
|
||||
return Collections.newSetFromMap(newIdentityMap());
|
||||
import jdk.tools.jaotc.binformat.macho.MachO;
|
||||
import jdk.tools.jaotc.binformat.macho.MachO.version_min_command;
|
||||
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
|
||||
|
||||
public class MachOVersion {
|
||||
ByteBuffer version;
|
||||
|
||||
public MachOVersion() {
|
||||
version = MachOByteBuffer.allocate(version_min_command.totalsize);
|
||||
|
||||
version.putInt(version_min_command.cmd.off, version_min_command.LC_VERSION_MIN_MACOSX);
|
||||
version.putInt(version_min_command.cmdsize.off, version_min_command.totalsize);
|
||||
version.putInt(version_min_command.version.off, (10 << 16) | (10 << 8)); /* MacOSX 10.10 */
|
||||
version.putInt(version_min_command.sdk.off, 0); /* N/A SDK */
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Map<K, V> newIdentityMap() {
|
||||
return new IdentityHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Map<K, V> newIdentityMap(int expectedMaxSize) {
|
||||
return new IdentityHashMap<>(expectedMaxSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Map<K, V> newIdentityMap(Map<K, V> initFrom) {
|
||||
return new IdentityHashMap<>(initFrom);
|
||||
public byte[] getArray() {
|
||||
return version.array();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,422 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.pecoff;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.tools.jaotc.binformat.Container;
|
||||
import jdk.tools.jaotc.binformat.BinaryContainer;
|
||||
import jdk.tools.jaotc.binformat.ByteContainer;
|
||||
import jdk.tools.jaotc.binformat.CodeContainer;
|
||||
import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
|
||||
import jdk.tools.jaotc.binformat.Relocation;
|
||||
import jdk.tools.jaotc.binformat.Relocation.RelocType;
|
||||
import jdk.tools.jaotc.binformat.Symbol;
|
||||
import jdk.tools.jaotc.binformat.NativeSymbol;
|
||||
import jdk.tools.jaotc.binformat.Symbol.Binding;
|
||||
import jdk.tools.jaotc.binformat.Symbol.Kind;
|
||||
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoff;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoffSymbol;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoffTargetInfo;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_FILE_HEADER;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SECTION_HEADER;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SYMBOL;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_RELOCATION;
|
||||
|
||||
public class JPECoffRelocObject {
|
||||
|
||||
private final BinaryContainer binContainer;
|
||||
|
||||
private final PECoffContainer pecoffContainer;
|
||||
|
||||
private final int segmentSize;
|
||||
|
||||
public JPECoffRelocObject(BinaryContainer binContainer, String outputFileName, String aotVersion) {
|
||||
this.binContainer = binContainer;
|
||||
this.pecoffContainer = new PECoffContainer(outputFileName, aotVersion);
|
||||
this.segmentSize = binContainer.getCodeSegmentSize();
|
||||
}
|
||||
|
||||
private PECoffSection createByteSection(ArrayList<PECoffSection>sections,
|
||||
String sectName,
|
||||
byte [] scnData,
|
||||
boolean hasRelocs,
|
||||
int scnFlags) {
|
||||
|
||||
PECoffSection sect = new PECoffSection(sectName,
|
||||
scnData,
|
||||
scnFlags,
|
||||
hasRelocs,
|
||||
sections.size());
|
||||
// Add this section to our list
|
||||
sections.add(sect);
|
||||
|
||||
return (sect);
|
||||
}
|
||||
|
||||
private void createByteSection(ArrayList<PECoffSection>sections,
|
||||
ByteContainer c, int scnFlags) {
|
||||
PECoffSection sect;
|
||||
boolean hasRelocs = c.hasRelocations();
|
||||
byte[] scnData = c.getByteArray();
|
||||
|
||||
sect = createByteSection(sections, c.getContainerName(),
|
||||
scnData, hasRelocs,
|
||||
scnFlags);
|
||||
|
||||
c.setSectionId(sect.getSectionId());
|
||||
}
|
||||
|
||||
private void createCodeSection(ArrayList<PECoffSection>sections, CodeContainer c) {
|
||||
createByteSection(sections, c, IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ |
|
||||
IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_EXECUTE |
|
||||
IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_16BYTES |
|
||||
IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_CODE);
|
||||
}
|
||||
|
||||
private void createReadOnlySection(ArrayList<PECoffSection>sections, ReadOnlyDataContainer c) {
|
||||
createByteSection(sections, c, IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ |
|
||||
IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_16BYTES |
|
||||
IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_INITIALIZED_DATA);
|
||||
}
|
||||
|
||||
private void createReadWriteSection(ArrayList<PECoffSection>sections, ByteContainer c) {
|
||||
int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ |
|
||||
IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_WRITE |
|
||||
IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_8BYTES;
|
||||
|
||||
if (c.getByteArray().length > 0)
|
||||
scnFlags |= IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_INITIALIZED_DATA;
|
||||
else
|
||||
scnFlags |= IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_UNINITIALIZED_DATA;
|
||||
|
||||
createByteSection(sections, c, scnFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an PECoff relocatable object
|
||||
*
|
||||
* @param relocationTable
|
||||
* @param symbols
|
||||
* @throws IOException throws {@code IOException} as a result of file system access failures.
|
||||
*/
|
||||
public void createPECoffRelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException {
|
||||
ArrayList<PECoffSection> sections = new ArrayList<PECoffSection>();
|
||||
|
||||
// Create text section
|
||||
createCodeSection(sections, binContainer.getCodeContainer());
|
||||
createReadOnlySection(sections, binContainer.getMetaspaceNamesContainer());
|
||||
createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer());
|
||||
createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer());
|
||||
createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer());
|
||||
createReadWriteSection(sections, binContainer.getMetaspaceGotContainer());
|
||||
createReadWriteSection(sections, binContainer.getMetadataGotContainer());
|
||||
createReadWriteSection(sections, binContainer.getMethodStateContainer());
|
||||
createReadWriteSection(sections, binContainer.getOopGotContainer());
|
||||
createReadWriteSection(sections, binContainer.getMethodMetadataContainer());
|
||||
createReadOnlySection(sections, binContainer.getStubsOffsetsContainer());
|
||||
createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer());
|
||||
createReadOnlySection(sections, binContainer.getCodeSegmentsContainer());
|
||||
createReadOnlySection(sections, binContainer.getConstantDataContainer());
|
||||
createReadOnlySection(sections, binContainer.getConfigContainer());
|
||||
|
||||
// createExternalLinkage();
|
||||
|
||||
createCodeSection(sections, binContainer.getExtLinkageContainer());
|
||||
createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer());
|
||||
|
||||
// Allocate PECoff Header
|
||||
PECoffHeader header = new PECoffHeader();
|
||||
|
||||
// Get PECoff symbol data from BinaryContainer object's symbol tables
|
||||
PECoffSymtab symtab = createPECoffSymbolTables(sections, symbols);
|
||||
|
||||
// Add Linker Directives Section
|
||||
createByteSection(sections, ".drectve",
|
||||
symtab.getDirectiveArray(), false,
|
||||
IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_INFO |
|
||||
IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_REMOVE |
|
||||
IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_1BYTES);
|
||||
|
||||
// Create the Relocation Tables
|
||||
PECoffRelocTable pecoffRelocs = createPECoffRelocTable(sections, relocationTable);
|
||||
|
||||
// File Output Order
|
||||
//
|
||||
// HEADER (Need address of Symbol Table + symbol count)
|
||||
// SECTIONS (Need pointer to Section Data, Relocation Table)
|
||||
// DIRECTIVES
|
||||
// SYMBOL TABLE
|
||||
// SYMBOLS
|
||||
// SECTION DATA
|
||||
// RELOCATION TABLE
|
||||
|
||||
// Calculate Offset for Symbol table
|
||||
int file_offset = IMAGE_FILE_HEADER.totalsize +
|
||||
(IMAGE_SECTION_HEADER.totalsize*sections.size());
|
||||
|
||||
// Update Header fields
|
||||
header.setSectionCount(sections.size());
|
||||
header.setSymbolCount(symtab.getSymtabCount());
|
||||
header.setSymbolOff(file_offset);
|
||||
|
||||
// Calculate file offset for first section
|
||||
file_offset += ((symtab.getSymtabCount() * IMAGE_SYMBOL.totalsize) +
|
||||
symtab.getStrtabSize());
|
||||
// And round it up
|
||||
file_offset = (file_offset + (sections.get(0).getDataAlign()-1)) &
|
||||
~((sections.get(0).getDataAlign()-1));
|
||||
|
||||
// Calc file offsets for section data
|
||||
for (int i = 0; i < sections.size(); i++) {
|
||||
PECoffSection sect = sections.get(i);
|
||||
file_offset = (file_offset + (sect.getDataAlign()-1)) &
|
||||
~((sect.getDataAlign()-1));
|
||||
sect.setOffset(file_offset);
|
||||
file_offset += sect.getSize();
|
||||
}
|
||||
|
||||
// Update relocation sizing information in each section
|
||||
for (int i = 0; i < sections.size(); i++) {
|
||||
PECoffSection sect = sections.get(i);
|
||||
if (sect.hasRelocations()) {
|
||||
int nreloc = pecoffRelocs.getNumRelocs(i);
|
||||
sect.setReloff(file_offset);
|
||||
sect.setRelcount(nreloc);
|
||||
// extended relocations add an addition entry
|
||||
if (nreloc > 0xFFFF) nreloc++;
|
||||
file_offset += (nreloc * IMAGE_RELOCATION.totalsize);
|
||||
}
|
||||
}
|
||||
|
||||
// Write out the Header
|
||||
pecoffContainer.writeBytes(header.getArray());
|
||||
|
||||
// Write out the section table
|
||||
for (int i = 0; i < sections.size(); i++) {
|
||||
PECoffSection sect = sections.get(i);
|
||||
pecoffContainer.writeBytes(sect.getArray(), PECoffSection.getShdrAlign());
|
||||
}
|
||||
|
||||
// Write out the symbol table and string table
|
||||
pecoffContainer.writeBytes(symtab.getSymtabArray(), 4);
|
||||
pecoffContainer.writeBytes(symtab.getStrtabArray(), 1);
|
||||
|
||||
// Write out each section contents
|
||||
for (int i = 0; i < sections.size(); i++) {
|
||||
PECoffSection sect = sections.get(i);
|
||||
pecoffContainer.writeBytes(sect.getDataArray(), sect.getDataAlign());
|
||||
}
|
||||
|
||||
// Write out Relocation Tables
|
||||
for (int i = 0; i < sections.size(); i++) {
|
||||
if (pecoffRelocs.getNumRelocs(i) > 0) {
|
||||
pecoffContainer.writeBytes(pecoffRelocs.getRelocData(i));
|
||||
}
|
||||
}
|
||||
pecoffContainer.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct PECoff symbol data from BinaryContainer object's symbol tables. Both dynamic PECoff
|
||||
* symbol table and PECoff symbol table are created from BinaryContainer's symbol info.
|
||||
*
|
||||
* @param symbols
|
||||
*/
|
||||
private PECoffSymtab createPECoffSymbolTables(ArrayList<PECoffSection> sections, Collection<Symbol> symbols) {
|
||||
PECoffSymtab symtab = new PECoffSymtab();
|
||||
|
||||
// First, create the initial null symbol. This is a local symbol.
|
||||
// symtab.addSymbolEntry("", (byte)0, (byte)0, (byte)0, 0, 0);
|
||||
|
||||
// Now create PECoff symbol entries for all symbols.
|
||||
for (Symbol symbol : symbols) {
|
||||
// Get the index of section this symbol is defined in.
|
||||
int secHdrIndex = symbol.getSection().getSectionId();
|
||||
PECoffSymbol pecoffSymbol = symtab.addSymbolEntry(symbol.getName(), getPECoffTypeOf(symbol), getPECoffClassOf(symbol), (byte)secHdrIndex, symbol.getOffset(), symbol.getSize());
|
||||
symbol.setNativeSymbol((NativeSymbol)pecoffSymbol);
|
||||
}
|
||||
return (symtab);
|
||||
}
|
||||
|
||||
private static byte getPECoffTypeOf(Symbol sym) {
|
||||
Kind kind = sym.getKind();
|
||||
if (kind == Symbol.Kind.NATIVE_FUNCTION || kind == Symbol.Kind.JAVA_FUNCTION) {
|
||||
return IMAGE_SYMBOL.IMAGE_SYM_DTYPE_FUNCTION;
|
||||
}
|
||||
return IMAGE_SYMBOL.IMAGE_SYM_DTYPE_NONE;
|
||||
}
|
||||
|
||||
private static byte getPECoffClassOf(Symbol sym) {
|
||||
Binding binding = sym.getBinding();
|
||||
if (binding == Symbol.Binding.GLOBAL) {
|
||||
return IMAGE_SYMBOL.IMAGE_SYM_CLASS_EXTERNAL;
|
||||
}
|
||||
return IMAGE_SYMBOL.IMAGE_SYM_CLASS_STATIC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a PECoff relocation table from BinaryContainer object's relocation tables.
|
||||
*
|
||||
* @param sections
|
||||
* @param relocationTable
|
||||
*/
|
||||
private PECoffRelocTable createPECoffRelocTable(ArrayList<PECoffSection> sections,
|
||||
Map<Symbol, List<Relocation>> relocationTable) {
|
||||
|
||||
PECoffRelocTable pecoffRelocTable = new PECoffRelocTable(sections.size());
|
||||
/*
|
||||
* For each of the symbols with associated relocation records, create a PECoff relocation
|
||||
* entry.
|
||||
*/
|
||||
for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) {
|
||||
List<Relocation> relocs = entry.getValue();
|
||||
Symbol symbol = entry.getKey();
|
||||
|
||||
for (Relocation reloc : relocs) {
|
||||
createRelocation(symbol, reloc, pecoffRelocTable);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) {
|
||||
createRelocation(entry.getKey(), entry.getValue(), pecoffRelocTable);
|
||||
}
|
||||
|
||||
return (pecoffRelocTable);
|
||||
}
|
||||
|
||||
private void createRelocation(Symbol symbol, Relocation reloc, PECoffRelocTable pecoffRelocTable) {
|
||||
RelocType relocType = reloc.getType();
|
||||
|
||||
int pecoffRelocType = getPECoffRelocationType(relocType);
|
||||
PECoffSymbol sym = (PECoffSymbol)symbol.getNativeSymbol();
|
||||
int symno = sym.getIndex();
|
||||
int sectindex = reloc.getSection().getSectionId();
|
||||
int offset = reloc.getOffset();
|
||||
int addend = 0;
|
||||
|
||||
switch (relocType) {
|
||||
case FOREIGN_CALL_DIRECT:
|
||||
case JAVA_CALL_DIRECT:
|
||||
case STUB_CALL_DIRECT:
|
||||
case FOREIGN_CALL_INDIRECT_GOT: {
|
||||
// Create relocation entry
|
||||
addend = -4; // Size in bytes of the patch location
|
||||
// Relocation should be applied at the location after call operand
|
||||
offset = offset + reloc.getSize() + addend;
|
||||
break;
|
||||
}
|
||||
case FOREIGN_CALL_DIRECT_FAR: {
|
||||
// Create relocation entry
|
||||
addend = -8; // Size in bytes of the patch location
|
||||
// Relocation should be applied at the location after call operand
|
||||
// 10 = 2 (jmp [r]) + 8 (imm64)
|
||||
offset = offset + reloc.getSize() + addend - 2;
|
||||
break;
|
||||
}
|
||||
case FOREIGN_CALL_INDIRECT:
|
||||
case JAVA_CALL_INDIRECT:
|
||||
case STUB_CALL_INDIRECT: {
|
||||
// Do nothing.
|
||||
return;
|
||||
}
|
||||
case EXTERNAL_DATA_REFERENCE_FAR: {
|
||||
// Create relocation entry
|
||||
addend = -4; // Size of 32-bit address of the GOT
|
||||
/*
|
||||
* Relocation should be applied before the test instruction to the move instruction.
|
||||
* offset points to the test instruction after the instruction that loads
|
||||
* the address of polling page. So set the offset appropriately.
|
||||
*/
|
||||
offset = offset + addend;
|
||||
break;
|
||||
}
|
||||
case METASPACE_GOT_REFERENCE:
|
||||
case EXTERNAL_PLT_TO_GOT:
|
||||
case STATIC_STUB_TO_STATIC_METHOD:
|
||||
case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: {
|
||||
addend = -4; // Size of 32-bit address of the GOT
|
||||
/*
|
||||
* Relocation should be applied before the test instruction to
|
||||
* the move instruction. reloc.getOffset() points to the
|
||||
* test instruction after the instruction that loads the
|
||||
* address of polling page. So set the offset appropriately.
|
||||
*/
|
||||
offset = offset + addend;
|
||||
break;
|
||||
}
|
||||
case EXTERNAL_GOT_TO_PLT:
|
||||
case LOADTIME_ADDRESS: {
|
||||
// this is load time relocations
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new InternalError("Unhandled relocation type: " + relocType);
|
||||
}
|
||||
pecoffRelocTable.createRelocationEntry(sectindex, offset, symno, pecoffRelocType);
|
||||
}
|
||||
|
||||
// Return IMAGE_RELOCATION Type based on relocType
|
||||
private static int getPECoffRelocationType(RelocType relocType) {
|
||||
int pecoffRelocType = 0; // R_<ARCH>_NONE if #define'd to 0 for all values of ARCH
|
||||
switch (PECoffTargetInfo.getPECoffArch()) {
|
||||
case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64:
|
||||
if (relocType == RelocType.FOREIGN_CALL_DIRECT ||
|
||||
relocType == RelocType.JAVA_CALL_DIRECT ||
|
||||
relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
|
||||
pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32;
|
||||
} else if (relocType == RelocType.STUB_CALL_DIRECT) {
|
||||
pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32;
|
||||
} else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) {
|
||||
pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ADDR64;
|
||||
} else if (relocType == RelocType.FOREIGN_CALL_INDIRECT ||
|
||||
relocType == RelocType.JAVA_CALL_INDIRECT ||
|
||||
relocType == RelocType.STUB_CALL_INDIRECT) {
|
||||
pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ABSOLUTE;
|
||||
} else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) {
|
||||
pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32;
|
||||
} else if (relocType == RelocType.METASPACE_GOT_REFERENCE ||
|
||||
relocType == RelocType.EXTERNAL_PLT_TO_GOT ||
|
||||
relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD ||
|
||||
relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) {
|
||||
pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32;
|
||||
} else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT ||
|
||||
relocType == RelocType.LOADTIME_ADDRESS) {
|
||||
pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ADDR64;
|
||||
} else {
|
||||
assert false : "Unhandled relocation type: " + relocType;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
System.out.println("Relocation Type mapping: Unhandled architecture");
|
||||
}
|
||||
return pecoffRelocType;
|
||||
}
|
||||
}
|
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.pecoff;
|
||||
|
||||
/**
|
||||
*
|
||||
* Support for the creation of Coff files.
|
||||
* Current support is limited to 64 bit x86_64.
|
||||
*
|
||||
*/
|
||||
|
||||
public class PECoff {
|
||||
|
||||
/**
|
||||
* IMAGE_FILE_HEADER structure defines
|
||||
*/
|
||||
public enum IMAGE_FILE_HEADER {
|
||||
Machine( 0, 2),
|
||||
NumberOfSections( 2, 2),
|
||||
TimeDateStamp( 4, 4),
|
||||
PointerToSymbolTable( 8, 4),
|
||||
NumberOfSymbols(12, 4),
|
||||
SizeOfOptionalHeader(16, 2),
|
||||
Characteristics(18, 2);
|
||||
|
||||
public final int off;
|
||||
public final int sz;
|
||||
|
||||
IMAGE_FILE_HEADER(int offset, int size) {
|
||||
this.off = offset;
|
||||
this.sz = size;
|
||||
}
|
||||
|
||||
public static int totalsize = 20;
|
||||
|
||||
/**
|
||||
* IMAGE_FILE_HEADER defines
|
||||
*/
|
||||
|
||||
/**
|
||||
* Machine
|
||||
*/
|
||||
public static final char IMAGE_FILE_MACHINE_UNKNOWN = 0x0;
|
||||
public static final char IMAGE_FILE_MACHINE_AMD64 = 0x8664;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* IMAGE_SECTION_HEADER structure defines
|
||||
*/
|
||||
public enum IMAGE_SECTION_HEADER {
|
||||
Name( 0, 8),
|
||||
PhysicalAddress( 8, 4),
|
||||
VirtualSize( 8, 4),
|
||||
VirtualAddress(12, 4),
|
||||
SizeOfRawData(16, 4),
|
||||
PointerToRawData(20, 4),
|
||||
PointerToRelocations(24, 4),
|
||||
PointerToLinenumbers(28, 4),
|
||||
NumberOfRelocations(32, 2),
|
||||
NumberOfLinenumbers(34, 2),
|
||||
Characteristics(36, 4);
|
||||
|
||||
public final int off;
|
||||
public final int sz;
|
||||
|
||||
IMAGE_SECTION_HEADER(int offset, int size) {
|
||||
this.off = offset;
|
||||
this.sz = size;
|
||||
}
|
||||
|
||||
public static int totalsize = 40;
|
||||
|
||||
/**
|
||||
* IMAGE_SECTION_HEADER defines
|
||||
*/
|
||||
|
||||
/**
|
||||
* Characteristics
|
||||
*/
|
||||
public static final int IMAGE_SCN_CNT_CODE = 0x20;
|
||||
public static final int IMAGE_SCN_CNT_INITIALIZED_DATA = 0x40;
|
||||
public static final int IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x80;
|
||||
public static final int IMAGE_SCN_LNK_COMDAT = 0x1000;
|
||||
public static final int IMAGE_SCN_LNK_INFO = 0x200;
|
||||
public static final int IMAGE_SCN_LNK_REMOVE = 0x800;
|
||||
|
||||
public static final int IMAGE_SCN_ALIGN_1BYTES = 0x100000;
|
||||
public static final int IMAGE_SCN_ALIGN_2BYTES = 0x200000;
|
||||
public static final int IMAGE_SCN_ALIGN_4BYTES = 0x300000;
|
||||
public static final int IMAGE_SCN_ALIGN_8BYTES = 0x400000;
|
||||
public static final int IMAGE_SCN_ALIGN_16BYTES = 0x500000;
|
||||
public static final int IMAGE_SCN_ALIGN_MASK = 0xf00000;
|
||||
public static final int IMAGE_SCN_ALIGN_SHIFT = 20;
|
||||
|
||||
public static final int IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000;
|
||||
|
||||
public static final int IMAGE_SCN_MEM_SHARED = 0x10000000;
|
||||
public static final int IMAGE_SCN_MEM_EXECUTE = 0x20000000;
|
||||
public static final int IMAGE_SCN_MEM_READ = 0x40000000;
|
||||
public static final int IMAGE_SCN_MEM_WRITE = 0x80000000;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Symbol table entry definitions
|
||||
*
|
||||
* IMAGE_SYMBOL structure defines
|
||||
*/
|
||||
public enum IMAGE_SYMBOL {
|
||||
ShortName( 0, 8),
|
||||
Short( 0, 4),
|
||||
Long( 4, 4),
|
||||
Value( 8, 4),
|
||||
SectionNumber(12, 2),
|
||||
Type(14, 2),
|
||||
StorageClass(16, 1),
|
||||
NumberOfAuxSymbols(17, 1);
|
||||
|
||||
public final int off;
|
||||
public final int sz;
|
||||
|
||||
IMAGE_SYMBOL(int offset, int size) {
|
||||
this.off = offset;
|
||||
this.sz = size;
|
||||
}
|
||||
|
||||
public static int totalsize = 18;
|
||||
|
||||
/**
|
||||
* Type
|
||||
*/
|
||||
public static final int IMAGE_SYM_DTYPE_NONE = 0x0;
|
||||
public static final int IMAGE_SYM_DTYPE_FUNCTION = 0x20;
|
||||
|
||||
/**
|
||||
* StorageClass
|
||||
*/
|
||||
public static final int IMAGE_SYM_CLASS_NULL = 0x0;
|
||||
public static final int IMAGE_SYM_CLASS_EXTERNAL = 0x2;
|
||||
public static final int IMAGE_SYM_CLASS_STATIC = 0x3;
|
||||
public static final int IMAGE_SYM_CLASS_LABEL = 0x6;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* IMAGE_RELOCATION structure defines
|
||||
*/
|
||||
public enum IMAGE_RELOCATION {
|
||||
VirtualAddress( 0, 4),
|
||||
SymbolTableIndex( 4, 4),
|
||||
Type( 8, 2);
|
||||
|
||||
public final int off;
|
||||
public final int sz;
|
||||
|
||||
IMAGE_RELOCATION(int offset, int size) {
|
||||
this.off = offset;
|
||||
this.sz = size;
|
||||
}
|
||||
|
||||
public static int totalsize = 10;
|
||||
|
||||
/**
|
||||
* Relocation types
|
||||
*/
|
||||
public static final int IMAGE_REL_AMD64_ABSOLUTE = 0x0;
|
||||
public static final int IMAGE_REL_AMD64_ADDR32 = 0x2;
|
||||
public static final int IMAGE_REL_AMD64_ADDR64 = 0x1;
|
||||
public static final int IMAGE_REL_AMD64_REL32 = 0x4;
|
||||
public static final int IMAGE_REL_AMD64_REL32_1 = 0x5;
|
||||
public static final int IMAGE_REL_AMD64_REL32_2 = 0x6;
|
||||
public static final int IMAGE_REL_AMD64_REL32_3 = 0x7;
|
||||
public static final int IMAGE_REL_AMD64_REL32_4 = 0x8;
|
||||
public static final int IMAGE_REL_AMD64_REL32_5 = 0x9;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -20,11 +20,19 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.salver.data;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
package jdk.tools.jaotc.binformat.pecoff;
|
||||
|
||||
public class DataDict extends LinkedHashMap<Object, Object> {
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public class PECoffByteBuffer {
|
||||
|
||||
public static ByteBuffer allocate(int size) {
|
||||
ByteBuffer buf = ByteBuffer.allocate(size);
|
||||
// Only support Little Endian on Windows
|
||||
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||
return (buf);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.pecoff;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
public class PECoffContainer {
|
||||
|
||||
File outputFile;
|
||||
FileOutputStream outputStream;
|
||||
long fileOffset;
|
||||
|
||||
public PECoffContainer(String fileName, String aotVersion) {
|
||||
String baseName;
|
||||
|
||||
outputFile = new File(fileName);
|
||||
if (outputFile.exists()) {
|
||||
outputFile.delete();
|
||||
}
|
||||
|
||||
try {
|
||||
outputStream = new FileOutputStream(outputFile);
|
||||
} catch (Exception e) {
|
||||
System.out.println("PECoffContainer: Can't create file " + fileName);
|
||||
}
|
||||
fileOffset = 0;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
outputStream.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println("PECoffContainer: close failed");
|
||||
}
|
||||
}
|
||||
|
||||
public void writeBytes(byte [] bytes) {
|
||||
if (bytes == null) return;
|
||||
try {
|
||||
outputStream.write(bytes);
|
||||
} catch (Exception e) {
|
||||
System.out.println("PECoffContainer: writeBytes failed");
|
||||
}
|
||||
fileOffset += bytes.length;
|
||||
}
|
||||
|
||||
// Write bytes to output file with up front alignment padding
|
||||
public void writeBytes(byte [] bytes, int alignment) {
|
||||
if (bytes == null) return;
|
||||
try {
|
||||
// Pad to alignment
|
||||
while ((fileOffset & (long)(alignment-1)) != 0) {
|
||||
outputStream.write(0);
|
||||
fileOffset++;
|
||||
}
|
||||
outputStream.write(bytes);
|
||||
} catch (Exception e) {
|
||||
System.out.println("PECoffContainer: writeBytes failed");
|
||||
}
|
||||
fileOffset += bytes.length;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.pecoff;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoff;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_FILE_HEADER;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoffTargetInfo;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
|
||||
|
||||
public class PECoffHeader {
|
||||
ByteBuffer header;
|
||||
|
||||
public PECoffHeader() {
|
||||
header = PECoffByteBuffer.allocate(IMAGE_FILE_HEADER.totalsize);
|
||||
|
||||
header.putChar(IMAGE_FILE_HEADER.Machine.off, IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64);
|
||||
header.putInt(IMAGE_FILE_HEADER.TimeDateStamp.off, (int)(System.currentTimeMillis()/1000));
|
||||
header.putInt(IMAGE_FILE_HEADER.PointerToSymbolTable.off, 0);
|
||||
header.putInt(IMAGE_FILE_HEADER.NumberOfSymbols.off, 0);
|
||||
header.putChar(IMAGE_FILE_HEADER.SizeOfOptionalHeader.off, (char)0);
|
||||
header.putChar(IMAGE_FILE_HEADER.Characteristics.off, (char)0);
|
||||
|
||||
}
|
||||
|
||||
// Update header with the number of total sections
|
||||
public void setSectionCount(int count) {
|
||||
header.putChar(IMAGE_FILE_HEADER.NumberOfSections.off, (char)count);
|
||||
}
|
||||
|
||||
// Update header with the number of total symbols
|
||||
public void setSymbolCount(int count) {
|
||||
header.putInt(IMAGE_FILE_HEADER.NumberOfSymbols.off, count);
|
||||
}
|
||||
|
||||
// Update header with the offset of symbol table
|
||||
public void setSymbolOff(int offset) {
|
||||
header.putInt(IMAGE_FILE_HEADER.PointerToSymbolTable.off, offset);
|
||||
}
|
||||
|
||||
public byte[] getArray() {
|
||||
return header.array();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -20,38 +20,30 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.core.common.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
package jdk.tools.jaotc.binformat.pecoff;
|
||||
|
||||
/**
|
||||
* Mimic a set implementation with an ArrayList. Beneficial for small sets (compared to
|
||||
* {@link HashSet}).
|
||||
*/
|
||||
public class ArraySet<E> extends ArrayList<E> implements Set<E> {
|
||||
private static final long serialVersionUID = 4476957522387436654L;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public ArraySet() {
|
||||
super();
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoff;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_RELOCATION;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
|
||||
|
||||
public class PECoffRelocEntry {
|
||||
ByteBuffer entry;
|
||||
|
||||
public PECoffRelocEntry(int offset, int symno, int type) {
|
||||
|
||||
entry = PECoffByteBuffer.allocate(IMAGE_RELOCATION.totalsize);
|
||||
|
||||
entry.putInt(IMAGE_RELOCATION.VirtualAddress.off, offset);
|
||||
entry.putInt(IMAGE_RELOCATION.SymbolTableIndex.off, symno);
|
||||
entry.putChar(IMAGE_RELOCATION.Type.off, (char)type);
|
||||
}
|
||||
|
||||
public ArraySet(int i) {
|
||||
super(i);
|
||||
}
|
||||
|
||||
public ArraySet(Collection<? extends E> c) {
|
||||
super(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E e) {
|
||||
// avoid duplicated entries
|
||||
if (contains(e)) {
|
||||
return false;
|
||||
}
|
||||
return super.add(e);
|
||||
public byte[] getArray() {
|
||||
return entry.array();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.pecoff;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoff;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_RELOCATION;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoffRelocEntry;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
|
||||
|
||||
public class PECoffRelocTable {
|
||||
ArrayList<ArrayList<PECoffRelocEntry>> relocEntries;
|
||||
|
||||
public PECoffRelocTable(int numsects) {
|
||||
relocEntries = new ArrayList<ArrayList<PECoffRelocEntry>>(numsects);
|
||||
for (int i = 0; i < numsects; i++)
|
||||
relocEntries.add(new ArrayList<PECoffRelocEntry>());
|
||||
}
|
||||
|
||||
public void createRelocationEntry(int sectindex,
|
||||
int offset,
|
||||
int symno,
|
||||
int type) {
|
||||
|
||||
PECoffRelocEntry entry = new PECoffRelocEntry(offset,
|
||||
symno,
|
||||
type);
|
||||
relocEntries.get(sectindex).add(entry);
|
||||
}
|
||||
|
||||
public int getAlign() { return (4); }
|
||||
|
||||
public int getNumRelocs(int section_index) {
|
||||
return relocEntries.get(section_index).size();
|
||||
}
|
||||
|
||||
// Return the relocation entries for a single section
|
||||
// or null if no entries added to section
|
||||
public byte [] getRelocData(int section_index) {
|
||||
ArrayList<PECoffRelocEntry> entryList = relocEntries.get(section_index);
|
||||
int entryCount = entryList.size();
|
||||
int allocCount = entryCount;
|
||||
|
||||
if (entryCount == 0)
|
||||
return null;
|
||||
|
||||
if (entryCount > 0xFFFF)
|
||||
allocCount++;
|
||||
|
||||
ByteBuffer relocData = PECoffByteBuffer.allocate(allocCount * IMAGE_RELOCATION.totalsize);
|
||||
|
||||
// If number of relocs exceeds 65K, add the real size
|
||||
// in a dummy first reloc entry
|
||||
if (entryCount > 0xFFFF) {
|
||||
PECoffRelocEntry entry = new PECoffRelocEntry(allocCount, 0, 0);
|
||||
relocData.put(entry.getArray());
|
||||
}
|
||||
|
||||
// Copy each entry to a single ByteBuffer
|
||||
for (int i = 0; i < entryCount; i++) {
|
||||
PECoffRelocEntry entry = entryList.get(i);
|
||||
relocData.put(entry.getArray());
|
||||
}
|
||||
|
||||
return (relocData.array());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.pecoff;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoff;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SECTION_HEADER;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
|
||||
|
||||
public class PECoffSection {
|
||||
ByteBuffer section;
|
||||
byte [] data;
|
||||
boolean hasrelocations;
|
||||
int sectionIndex;
|
||||
int align;
|
||||
|
||||
public PECoffSection(String sectName, byte [] sectData, int sectFlags,
|
||||
boolean hasRelocations, int sectIndex) {
|
||||
|
||||
section = PECoffByteBuffer.allocate(IMAGE_SECTION_HEADER.totalsize);
|
||||
|
||||
// bug: If JVM.oop.got section is empty, VM exits since JVM.oop.got
|
||||
// symbol ends up as external forwarded reference.
|
||||
if (sectData.length == 0) sectData = new byte[8];
|
||||
|
||||
// Copy only Max allowed bytes to Section Entry
|
||||
byte [] Name = sectName.getBytes();
|
||||
int max = Name.length <= IMAGE_SECTION_HEADER.Name.sz ?
|
||||
Name.length : IMAGE_SECTION_HEADER.Name.sz;
|
||||
|
||||
section.put(Name, IMAGE_SECTION_HEADER.Name.off, max);
|
||||
|
||||
section.putInt(IMAGE_SECTION_HEADER.VirtualSize.off, 0);
|
||||
section.putInt(IMAGE_SECTION_HEADER.VirtualAddress.off, 0);
|
||||
section.putInt(IMAGE_SECTION_HEADER.SizeOfRawData.off, sectData.length);
|
||||
section.putInt(IMAGE_SECTION_HEADER.PointerToLinenumbers.off, 0);
|
||||
section.putChar(IMAGE_SECTION_HEADER.NumberOfLinenumbers.off, (char)0);
|
||||
|
||||
section.putInt(IMAGE_SECTION_HEADER.Characteristics.off, sectFlags);
|
||||
|
||||
// Extract alignment from Characteristics field
|
||||
int alignshift = (sectFlags & IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_MASK) >>
|
||||
IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_SHIFT;
|
||||
|
||||
// Use 8 byte alignment if not specified
|
||||
if (alignshift == 0)
|
||||
alignshift = 3;
|
||||
else
|
||||
--alignshift;
|
||||
|
||||
align = 1 << alignshift;
|
||||
|
||||
data = sectData;
|
||||
hasrelocations = hasRelocations;
|
||||
sectionIndex = sectIndex;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return section.getInt(IMAGE_SECTION_HEADER.SizeOfRawData.off);
|
||||
}
|
||||
|
||||
public int getDataAlign() {
|
||||
return (align);
|
||||
}
|
||||
|
||||
// Alignment requirements for the IMAGE_SECTION_HEADER structures
|
||||
public static int getShdrAlign() {
|
||||
return (4);
|
||||
}
|
||||
|
||||
public byte[] getArray() {
|
||||
return section.array();
|
||||
}
|
||||
|
||||
public byte[] getDataArray() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setOffset(long offset) {
|
||||
section.putInt(IMAGE_SECTION_HEADER.PointerToRawData.off, (int)offset);
|
||||
}
|
||||
|
||||
public long getOffset() {
|
||||
return (section.getInt(IMAGE_SECTION_HEADER.PointerToRawData.off));
|
||||
}
|
||||
|
||||
public void setReloff(int offset) {
|
||||
section.putInt(IMAGE_SECTION_HEADER.PointerToRelocations.off, offset);
|
||||
}
|
||||
|
||||
public void setRelcount(int count) {
|
||||
// If the number of relocs is larger than 65K, then set
|
||||
// the overflow bit. The real count will be written to
|
||||
// the first reloc entry for this section.
|
||||
if (count > 0xFFFF) {
|
||||
int flags;
|
||||
section.putChar(IMAGE_SECTION_HEADER.NumberOfRelocations.off, (char)0xFFFF);
|
||||
flags = section.getInt(IMAGE_SECTION_HEADER.Characteristics.off);
|
||||
flags |= IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_NRELOC_OVFL;
|
||||
section.putInt(IMAGE_SECTION_HEADER.Characteristics.off, flags);
|
||||
}
|
||||
else {
|
||||
section.putChar(IMAGE_SECTION_HEADER.NumberOfRelocations.off, (char)count);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasRelocations() {
|
||||
return hasrelocations;
|
||||
}
|
||||
|
||||
public int getSectionId() {
|
||||
return sectionIndex;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.pecoff;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.tools.jaotc.binformat.NativeSymbol;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoff;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SYMBOL;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
|
||||
|
||||
public class PECoffSymbol extends NativeSymbol {
|
||||
ByteBuffer sym;
|
||||
|
||||
public PECoffSymbol(int symbolindex, int strindex, byte type, byte storageclass,
|
||||
byte sectindex, long offset, long size) {
|
||||
super(symbolindex);
|
||||
sym = PECoffByteBuffer.allocate(IMAGE_SYMBOL.totalsize);
|
||||
|
||||
// We don't use short names
|
||||
sym.putInt(IMAGE_SYMBOL.Short.off, 0);
|
||||
|
||||
sym.putInt(IMAGE_SYMBOL.Long.off, strindex);
|
||||
sym.putInt(IMAGE_SYMBOL.Value.off, (int)offset);
|
||||
|
||||
// Section indexes start at 1 but we manage the index internally
|
||||
// as 0 relative except in this structure
|
||||
sym.putChar(IMAGE_SYMBOL.SectionNumber.off, (char)(sectindex+1));
|
||||
|
||||
sym.putChar(IMAGE_SYMBOL.Type.off, (char)type);
|
||||
sym.put(IMAGE_SYMBOL.StorageClass.off, storageclass);
|
||||
sym.put(IMAGE_SYMBOL.NumberOfAuxSymbols.off, (byte)0);
|
||||
}
|
||||
|
||||
public byte[] getArray() {
|
||||
return sym.array();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.binformat.pecoff;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoff;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SYMBOL;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoffSymbol;
|
||||
import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
|
||||
|
||||
public class PECoffSymtab {
|
||||
ArrayList<PECoffSymbol>symbols = new ArrayList<PECoffSymbol>();
|
||||
|
||||
/**
|
||||
* number of symbols added
|
||||
*/
|
||||
int symbolCount;
|
||||
|
||||
/**
|
||||
* String holding symbol table strings
|
||||
*/
|
||||
private StringBuilder strTabContent;
|
||||
|
||||
/**
|
||||
* Keeps track of bytes in string table since strTabContent.length()
|
||||
* is number of chars, not bytes.
|
||||
*/
|
||||
private int strTabNrOfBytes;
|
||||
|
||||
/**
|
||||
* String holding Linker Directives
|
||||
*/
|
||||
private StringBuilder directives;
|
||||
|
||||
public PECoffSymtab() {
|
||||
symbolCount = 0;
|
||||
strTabContent = new StringBuilder();
|
||||
directives = new StringBuilder();
|
||||
|
||||
// The first 4 bytes of the string table contain
|
||||
// the length of the table (including this length field).
|
||||
strTabNrOfBytes = 4;
|
||||
|
||||
// Make room for the 4 byte length field
|
||||
strTabContent.append('\0').append('\0').append('\0').append('\0');
|
||||
|
||||
// Linker Directives start with 3 spaces to signify ANSI
|
||||
directives.append(" ");
|
||||
}
|
||||
|
||||
public PECoffSymbol addSymbolEntry(String name, byte type, byte storageclass,
|
||||
byte secHdrIndex, long offset, long size) {
|
||||
// Get the current symbol index and append symbol name to string table.
|
||||
int index;
|
||||
PECoffSymbol sym;
|
||||
|
||||
if (name.isEmpty()) {
|
||||
index = 0;
|
||||
strTabContent.append('\0');
|
||||
strTabNrOfBytes += 1;
|
||||
sym = new PECoffSymbol(symbolCount, index, type, storageclass, secHdrIndex, offset, size);
|
||||
symbols.add(sym);
|
||||
} else {
|
||||
int nameSize = name.getBytes().length;
|
||||
|
||||
// We can't trust strTabContent.length() since that is
|
||||
// chars (UTF16), keep track of bytes on our own.
|
||||
index = strTabNrOfBytes;
|
||||
// strTabContent.append('_').append(name).append('\0');
|
||||
strTabContent.append(name).append('\0');
|
||||
strTabNrOfBytes += (nameSize + 1);
|
||||
|
||||
sym = new PECoffSymbol(symbolCount, index, type, storageclass, secHdrIndex, offset, size);
|
||||
symbols.add(sym);
|
||||
if (storageclass == IMAGE_SYMBOL.IMAGE_SYM_CLASS_EXTERNAL)
|
||||
addDirective(name, type);
|
||||
}
|
||||
symbolCount++;
|
||||
return (sym);
|
||||
}
|
||||
|
||||
private void addDirective(String name, byte type) {
|
||||
directives.append("/EXPORT:" + name);
|
||||
if(type != IMAGE_SYMBOL.IMAGE_SYM_DTYPE_FUNCTION) {
|
||||
directives.append(",DATA");
|
||||
}
|
||||
directives.append(" ");
|
||||
}
|
||||
|
||||
public int getSymtabCount() {
|
||||
return symbolCount;
|
||||
}
|
||||
|
||||
public int getStrtabSize() {
|
||||
return strTabNrOfBytes;
|
||||
}
|
||||
|
||||
// Return a byte array that contains the symbol table entries
|
||||
public byte[] getSymtabArray() {
|
||||
ByteBuffer symtabData = PECoffByteBuffer.allocate(symbolCount*IMAGE_SYMBOL.totalsize);
|
||||
symtabData.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
// copy all symbols
|
||||
for (int i = 0; i < symbolCount; i++ ) {
|
||||
PECoffSymbol sym = symbols.get(i);
|
||||
byte [] arr = sym.getArray();
|
||||
symtabData.put(arr);
|
||||
}
|
||||
return (symtabData.array());
|
||||
}
|
||||
|
||||
// Return the string table array
|
||||
public byte[] getStrtabArray() {
|
||||
byte [] strs = strTabContent.toString().getBytes();
|
||||
|
||||
// Update the size of the string table
|
||||
ByteBuffer buff = ByteBuffer.wrap(strs);
|
||||
buff.order(ByteOrder.LITTLE_ENDIAN);
|
||||
buff.putInt(0, strTabNrOfBytes);
|
||||
|
||||
return (strs);
|
||||
}
|
||||
|
||||
public byte[] getDirectiveArray() {
|
||||
return (directives.toString().getBytes());
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user