Refactoring of function types. Also fixes some library import bugs.
This commit is contained in:
parent
bdee924494
commit
f85b83709e
|
@ -23,7 +23,7 @@ using namespace alloy::runtime;
|
||||||
IVMFunction::IVMFunction(FunctionInfo* symbol_info) :
|
IVMFunction::IVMFunction(FunctionInfo* symbol_info) :
|
||||||
register_count_(0), intcode_count_(0), intcodes_(0),
|
register_count_(0), intcode_count_(0), intcodes_(0),
|
||||||
source_map_count_(0), source_map_(0),
|
source_map_count_(0), source_map_(0),
|
||||||
GuestFunction(symbol_info) {
|
Function(symbol_info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
IVMFunction::~IVMFunction() {
|
IVMFunction::~IVMFunction() {
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace backend {
|
||||||
namespace ivm {
|
namespace ivm {
|
||||||
|
|
||||||
|
|
||||||
class IVMFunction : public runtime::GuestFunction {
|
class IVMFunction : public runtime::Function {
|
||||||
public:
|
public:
|
||||||
IVMFunction(runtime::FunctionInfo* symbol_info);
|
IVMFunction(runtime::FunctionInfo* symbol_info);
|
||||||
virtual ~IVMFunction();
|
virtual ~IVMFunction();
|
||||||
|
|
|
@ -712,6 +712,13 @@ int Translate_CALL_INDIRECT_TRUE(TranslationContext& ctx, Instr* i) {
|
||||||
return DispatchToC(ctx, i, fns[i->src1.value->type]);
|
return DispatchToC(ctx, i, fns[i->src1.value->type]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t IntCode_CALL_EXTERN(IntCodeState& ics, const IntCode* i) {
|
||||||
|
return IntCode_CALL_XX(ics, i, i->src1_reg);
|
||||||
|
}
|
||||||
|
int Translate_CALL_EXTERN(TranslationContext& ctx, Instr* i) {
|
||||||
|
return DispatchToC(ctx, i, IntCode_CALL_EXTERN);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t IntCode_RETURN(IntCodeState& ics, const IntCode* i) {
|
uint32_t IntCode_RETURN(IntCodeState& ics, const IntCode* i) {
|
||||||
return IA_RETURN;
|
return IA_RETURN;
|
||||||
}
|
}
|
||||||
|
@ -4009,6 +4016,7 @@ static const TranslateFn dispatch_table[] = {
|
||||||
Translate_CALL_TRUE,
|
Translate_CALL_TRUE,
|
||||||
Translate_CALL_INDIRECT,
|
Translate_CALL_INDIRECT,
|
||||||
Translate_CALL_INDIRECT_TRUE,
|
Translate_CALL_INDIRECT_TRUE,
|
||||||
|
Translate_CALL_EXTERN,
|
||||||
Translate_RETURN,
|
Translate_RETURN,
|
||||||
Translate_RETURN_TRUE,
|
Translate_RETURN_TRUE,
|
||||||
|
|
||||||
|
|
|
@ -96,12 +96,6 @@ void Dummy() {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnimplementedExtern(void* raw_context, ExternFunction* extern_fn) {
|
|
||||||
// TODO(benvanik): generate this thunk at runtime? or a shim?
|
|
||||||
auto thread_state = *((ThreadState**)raw_context);
|
|
||||||
extern_fn->Call(thread_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t DynamicRegisterLoad(void* raw_context, uint32_t address) {
|
uint64_t DynamicRegisterLoad(void* raw_context, uint32_t address) {
|
||||||
auto thread_state = *((ThreadState**)raw_context);
|
auto thread_state = *((ThreadState**)raw_context);
|
||||||
auto cbs = thread_state->runtime()->access_callbacks();
|
auto cbs = thread_state->runtime()->access_callbacks();
|
||||||
|
@ -149,44 +143,30 @@ void* ResolveFunctionSymbol(void* raw_context, FunctionInfo* symbol_info) {
|
||||||
Function* fn = NULL;
|
Function* fn = NULL;
|
||||||
thread_state->runtime()->ResolveFunction(symbol_info->address(), &fn);
|
thread_state->runtime()->ResolveFunction(symbol_info->address(), &fn);
|
||||||
XEASSERTNOTNULL(fn);
|
XEASSERTNOTNULL(fn);
|
||||||
XEASSERT(fn->type() == Function::USER_FUNCTION);
|
|
||||||
auto x64_fn = (X64Function*)fn;
|
auto x64_fn = (X64Function*)fn;
|
||||||
return x64_fn->machine_code();
|
return x64_fn->machine_code();
|
||||||
}
|
}
|
||||||
void* ResolveFunctionAddress(void* raw_context, uint64_t target_address) {
|
void* ResolveFunctionAddress(void* raw_context, uint32_t target_address) {
|
||||||
// TODO(benvanik): generate this thunk at runtime? or a shim?
|
// TODO(benvanik): generate this thunk at runtime? or a shim?
|
||||||
auto thread_state = *((ThreadState**)raw_context);
|
auto thread_state = *((ThreadState**)raw_context);
|
||||||
|
|
||||||
Function* fn = NULL;
|
Function* fn = NULL;
|
||||||
thread_state->runtime()->ResolveFunction(target_address, &fn);
|
thread_state->runtime()->ResolveFunction(target_address, &fn);
|
||||||
XEASSERTNOTNULL(fn);
|
XEASSERTNOTNULL(fn);
|
||||||
XEASSERT(fn->type() == Function::USER_FUNCTION);
|
|
||||||
auto x64_fn = (X64Function*)fn;
|
auto x64_fn = (X64Function*)fn;
|
||||||
return x64_fn->machine_code();
|
return x64_fn->machine_code();
|
||||||
}
|
}
|
||||||
void IssueCall(X64Emitter& e, FunctionInfo* symbol_info, uint32_t flags) {
|
void IssueCall(X64Emitter& e, FunctionInfo* symbol_info, uint32_t flags) {
|
||||||
// If we are an extern function, we can directly insert a call.
|
|
||||||
auto fn = symbol_info->function();
|
auto fn = symbol_info->function();
|
||||||
if (fn && fn->type() == Function::EXTERN_FUNCTION) {
|
// Resolve address to the function to call and store in rax.
|
||||||
auto extern_fn = (ExternFunction*)fn;
|
|
||||||
if (extern_fn->handler()) {
|
|
||||||
e.mov(e.rdx, (uint64_t)extern_fn->arg0());
|
|
||||||
e.mov(e.r8, (uint64_t)extern_fn->arg1());
|
|
||||||
e.mov(e.rax, (uint64_t)extern_fn->handler());
|
|
||||||
} else {
|
|
||||||
// Unimplemented - call dummy.
|
|
||||||
e.mov(e.rdx, (uint64_t)extern_fn);
|
|
||||||
e.mov(e.rax, (uint64_t)UnimplementedExtern);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Generic call, resolve address.
|
|
||||||
// TODO(benvanik): caching/etc. For now this makes debugging easier.
|
// TODO(benvanik): caching/etc. For now this makes debugging easier.
|
||||||
e.mov(e.rdx, (uint64_t)symbol_info);
|
e.mov(e.rdx, (uint64_t)symbol_info);
|
||||||
e.mov(e.rax, (uint64_t)ResolveFunctionSymbol);
|
e.mov(e.rax, (uint64_t)ResolveFunctionSymbol);
|
||||||
e.call(e.rax);
|
e.call(e.rax);
|
||||||
e.mov(e.rcx, e.qword[e.rsp + 0]);
|
e.mov(e.rcx, e.qword[e.rsp + 0]);
|
||||||
e.mov(e.rdx, e.qword[e.rcx + 8]); // membase
|
e.mov(e.rdx, e.qword[e.rcx + 8]); // membase
|
||||||
}
|
|
||||||
|
// Actually jump/call to rax.
|
||||||
if (flags & CALL_TAIL) {
|
if (flags & CALL_TAIL) {
|
||||||
// TODO(benvanik): adjust stack?
|
// TODO(benvanik): adjust stack?
|
||||||
e.add(e.rsp, 72);
|
e.add(e.rsp, 72);
|
||||||
|
@ -198,6 +178,8 @@ void IssueCall(X64Emitter& e, FunctionInfo* symbol_info, uint32_t flags) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void IssueCallIndirect(X64Emitter& e, Value* target, uint32_t flags) {
|
void IssueCallIndirect(X64Emitter& e, Value* target, uint32_t flags) {
|
||||||
|
// Resolve address to the function to call and store in rax.
|
||||||
|
// TODO(benvanik): caching/etc. For now this makes debugging easier.
|
||||||
Reg64 r;
|
Reg64 r;
|
||||||
e.BeginOp(target, r, 0);
|
e.BeginOp(target, r, 0);
|
||||||
if (r != e.rdx) {
|
if (r != e.rdx) {
|
||||||
|
@ -208,6 +190,8 @@ void IssueCallIndirect(X64Emitter& e, Value* target, uint32_t flags) {
|
||||||
e.call(e.rax);
|
e.call(e.rax);
|
||||||
e.mov(e.rcx, e.qword[e.rsp + 0]);
|
e.mov(e.rcx, e.qword[e.rsp + 0]);
|
||||||
e.mov(e.rdx, e.qword[e.rcx + 8]); // membase
|
e.mov(e.rdx, e.qword[e.rcx + 8]); // membase
|
||||||
|
|
||||||
|
// Actually jump/call to rax.
|
||||||
if (flags & CALL_TAIL) {
|
if (flags & CALL_TAIL) {
|
||||||
// TODO(benvanik): adjust stack?
|
// TODO(benvanik): adjust stack?
|
||||||
e.add(e.rsp, 72);
|
e.add(e.rsp, 72);
|
||||||
|
@ -349,6 +333,17 @@ table->AddSequence(OPCODE_CALL_INDIRECT_TRUE, [](X64Emitter& e, Instr*& i) {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
table->AddSequence(OPCODE_CALL_EXTERN, [](X64Emitter& e, Instr*& i) {
|
||||||
|
auto symbol_info = i->src1.symbol_info;
|
||||||
|
XEASSERT(symbol_info->behavior() == FunctionInfo::BEHAVIOR_EXTERN);
|
||||||
|
XEASSERTNOTNULL(symbol_info->extern_handler());
|
||||||
|
e.mov(e.rdx, (uint64_t)symbol_info->extern_arg0());
|
||||||
|
e.mov(e.r8, (uint64_t)symbol_info->extern_arg1());
|
||||||
|
CallNative(e, symbol_info->extern_handler());
|
||||||
|
i = e.Advance(i);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
table->AddSequence(OPCODE_RETURN, [](X64Emitter& e, Instr*& i) {
|
table->AddSequence(OPCODE_RETURN, [](X64Emitter& e, Instr*& i) {
|
||||||
// If this is the last instruction in the last block, just let us
|
// If this is the last instruction in the last block, just let us
|
||||||
// fall through.
|
// fall through.
|
||||||
|
|
|
@ -21,7 +21,7 @@ using namespace alloy::runtime;
|
||||||
|
|
||||||
X64Function::X64Function(FunctionInfo* symbol_info) :
|
X64Function::X64Function(FunctionInfo* symbol_info) :
|
||||||
machine_code_(NULL), code_size_(0),
|
machine_code_(NULL), code_size_(0),
|
||||||
GuestFunction(symbol_info) {
|
Function(symbol_info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
X64Function::~X64Function() {
|
X64Function::~X64Function() {
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace backend {
|
||||||
namespace x64 {
|
namespace x64 {
|
||||||
|
|
||||||
|
|
||||||
class X64Function : public runtime::GuestFunction {
|
class X64Function : public runtime::Function {
|
||||||
public:
|
public:
|
||||||
X64Function(runtime::FunctionInfo* symbol_info);
|
X64Function(runtime::FunctionInfo* symbol_info);
|
||||||
virtual ~X64Function();
|
virtual ~X64Function();
|
||||||
|
|
|
@ -380,8 +380,8 @@ XEEMITTER(mcrf, 0x4C000000, XL )(PPCHIRBuilder& f, InstrData& i) {
|
||||||
// System linkage (A-24)
|
// System linkage (A-24)
|
||||||
|
|
||||||
XEEMITTER(sc, 0x44000002, SC )(PPCHIRBuilder& f, InstrData& i) {
|
XEEMITTER(sc, 0x44000002, SC )(PPCHIRBuilder& f, InstrData& i) {
|
||||||
XEINSTRNOTIMPLEMENTED();
|
f.CallExtern(f.symbol_info());
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -557,6 +557,13 @@ void HIRBuilder::CallIndirectTrue(
|
||||||
EndBlock();
|
EndBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HIRBuilder::CallExtern(FunctionInfo* symbol_info) {
|
||||||
|
Instr* i = AppendInstr(OPCODE_CALL_EXTERN_info, 0);
|
||||||
|
i->src1.symbol_info = symbol_info;
|
||||||
|
i->src2.value = i->src3.value = NULL;
|
||||||
|
EndBlock();
|
||||||
|
}
|
||||||
|
|
||||||
void HIRBuilder::Return() {
|
void HIRBuilder::Return() {
|
||||||
Instr* i = AppendInstr(OPCODE_RETURN_info, 0);
|
Instr* i = AppendInstr(OPCODE_RETURN_info, 0);
|
||||||
i->src1.value = i->src2.value = i->src3.value = NULL;
|
i->src1.value = i->src2.value = i->src3.value = NULL;
|
||||||
|
|
|
@ -74,6 +74,7 @@ public:
|
||||||
uint32_t call_flags = 0);
|
uint32_t call_flags = 0);
|
||||||
void CallIndirect(Value* value, uint32_t call_flags = 0);
|
void CallIndirect(Value* value, uint32_t call_flags = 0);
|
||||||
void CallIndirectTrue(Value* cond, Value* value, uint32_t call_flags = 0);
|
void CallIndirectTrue(Value* cond, Value* value, uint32_t call_flags = 0);
|
||||||
|
void CallExtern(runtime::FunctionInfo* symbol_info);
|
||||||
void Return();
|
void Return();
|
||||||
void ReturnTrue(Value* cond);
|
void ReturnTrue(Value* cond);
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,7 @@ enum Opcode {
|
||||||
OPCODE_CALL_TRUE,
|
OPCODE_CALL_TRUE,
|
||||||
OPCODE_CALL_INDIRECT,
|
OPCODE_CALL_INDIRECT,
|
||||||
OPCODE_CALL_INDIRECT_TRUE,
|
OPCODE_CALL_INDIRECT_TRUE,
|
||||||
|
OPCODE_CALL_EXTERN,
|
||||||
OPCODE_RETURN,
|
OPCODE_RETURN,
|
||||||
OPCODE_RETURN_TRUE,
|
OPCODE_RETURN_TRUE,
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,12 @@ DEFINE_OPCODE(
|
||||||
OPCODE_SIG_X_V_V,
|
OPCODE_SIG_X_V_V,
|
||||||
OPCODE_FLAG_BRANCH);
|
OPCODE_FLAG_BRANCH);
|
||||||
|
|
||||||
|
DEFINE_OPCODE(
|
||||||
|
OPCODE_CALL_EXTERN,
|
||||||
|
"call_extern",
|
||||||
|
OPCODE_SIG_X_S,
|
||||||
|
OPCODE_FLAG_BRANCH);
|
||||||
|
|
||||||
DEFINE_OPCODE(
|
DEFINE_OPCODE(
|
||||||
OPCODE_RETURN,
|
OPCODE_RETURN,
|
||||||
"return",
|
"return",
|
||||||
|
|
|
@ -17,8 +17,9 @@ using namespace alloy;
|
||||||
using namespace alloy::runtime;
|
using namespace alloy::runtime;
|
||||||
|
|
||||||
|
|
||||||
Function::Function(Type type, uint64_t address) :
|
Function::Function(FunctionInfo* symbol_info) :
|
||||||
type_(type), address_(address), debug_info_(0) {
|
address_(symbol_info->address()),
|
||||||
|
symbol_info_(symbol_info), debug_info_(0) {
|
||||||
// TODO(benvanik): create on demand?
|
// TODO(benvanik): create on demand?
|
||||||
lock_ = AllocMutex();
|
lock_ = AllocMutex();
|
||||||
}
|
}
|
||||||
|
@ -77,43 +78,27 @@ int Function::Call(ThreadState* thread_state) {
|
||||||
if (original_thread_state != thread_state) {
|
if (original_thread_state != thread_state) {
|
||||||
ThreadState::Bind(thread_state);
|
ThreadState::Bind(thread_state);
|
||||||
}
|
}
|
||||||
int result = CallImpl(thread_state);
|
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
if (symbol_info_->behavior() == FunctionInfo::BEHAVIOR_EXTERN) {
|
||||||
|
auto handler = symbol_info_->extern_handler();
|
||||||
|
if (handler) {
|
||||||
|
handler(thread_state->raw_context(),
|
||||||
|
symbol_info_->extern_arg0(),
|
||||||
|
symbol_info_->extern_arg1());
|
||||||
|
} else {
|
||||||
|
XELOGW("undefined extern call to %.8X %s",
|
||||||
|
symbol_info_->address(),
|
||||||
|
symbol_info_->name());
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CallImpl(thread_state);
|
||||||
|
}
|
||||||
|
|
||||||
if (original_thread_state != thread_state) {
|
if (original_thread_state != thread_state) {
|
||||||
ThreadState::Bind(original_thread_state);
|
ThreadState::Bind(original_thread_state);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExternFunction::ExternFunction(
|
|
||||||
uint64_t address, Handler handler, void* arg0, void* arg1) :
|
|
||||||
name_(0),
|
|
||||||
handler_(handler), arg0_(arg0), arg1_(arg1),
|
|
||||||
Function(Function::EXTERN_FUNCTION, address) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ExternFunction::~ExternFunction() {
|
|
||||||
if (name_) {
|
|
||||||
xe_free(name_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExternFunction::set_name(const char* name) {
|
|
||||||
name_ = xestrdupa(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ExternFunction::CallImpl(ThreadState* thread_state) {
|
|
||||||
if (!handler_) {
|
|
||||||
XELOGW("undefined extern call to %.8X %s", address(), name());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
handler_(thread_state->raw_context(), arg0_, arg1_);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
GuestFunction::GuestFunction(FunctionInfo* symbol_info) :
|
|
||||||
symbol_info_(symbol_info),
|
|
||||||
Function(Function::USER_FUNCTION, symbol_info->address()) {
|
|
||||||
}
|
|
||||||
|
|
||||||
GuestFunction::~GuestFunction() {
|
|
||||||
}
|
|
||||||
|
|
|
@ -24,17 +24,11 @@ class ThreadState;
|
||||||
|
|
||||||
class Function {
|
class Function {
|
||||||
public:
|
public:
|
||||||
enum Type {
|
Function(FunctionInfo* symbol_info);
|
||||||
UNKNOWN_FUNCTION = 0,
|
|
||||||
EXTERN_FUNCTION,
|
|
||||||
USER_FUNCTION,
|
|
||||||
};
|
|
||||||
public:
|
|
||||||
Function(Type type, uint64_t address);
|
|
||||||
virtual ~Function();
|
virtual ~Function();
|
||||||
|
|
||||||
Type type() const { return type_; }
|
|
||||||
uint64_t address() const { return address_; }
|
uint64_t address() const { return address_; }
|
||||||
|
FunctionInfo* symbol_info() const { return symbol_info_; }
|
||||||
|
|
||||||
DebugInfo* debug_info() const { return debug_info_; }
|
DebugInfo* debug_info() const { return debug_info_; }
|
||||||
void set_debug_info(DebugInfo* debug_info) { debug_info_ = debug_info; }
|
void set_debug_info(DebugInfo* debug_info) { debug_info_ = debug_info; }
|
||||||
|
@ -51,8 +45,8 @@ protected:
|
||||||
virtual int CallImpl(ThreadState* thread_state) = 0;
|
virtual int CallImpl(ThreadState* thread_state) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Type type_;
|
|
||||||
uint64_t address_;
|
uint64_t address_;
|
||||||
|
FunctionInfo* symbol_info_;
|
||||||
DebugInfo* debug_info_;
|
DebugInfo* debug_info_;
|
||||||
|
|
||||||
// TODO(benvanik): move elsewhere? DebugData?
|
// TODO(benvanik): move elsewhere? DebugData?
|
||||||
|
@ -61,43 +55,6 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class ExternFunction : public Function {
|
|
||||||
public:
|
|
||||||
typedef void(*Handler)(void* context, void* arg0, void* arg1);
|
|
||||||
public:
|
|
||||||
ExternFunction(uint64_t address, Handler handler, void* arg0, void* arg1);
|
|
||||||
virtual ~ExternFunction();
|
|
||||||
|
|
||||||
const char* name() const { return name_; }
|
|
||||||
void set_name(const char* name);
|
|
||||||
|
|
||||||
Handler handler() const { return handler_; }
|
|
||||||
void* arg0() const { return arg0_; }
|
|
||||||
void* arg1() const { return arg1_; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual int CallImpl(ThreadState* thread_state);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
char* name_;
|
|
||||||
Handler handler_;
|
|
||||||
void* arg0_;
|
|
||||||
void* arg1_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class GuestFunction : public Function {
|
|
||||||
public:
|
|
||||||
GuestFunction(FunctionInfo* symbol_info);
|
|
||||||
virtual ~GuestFunction();
|
|
||||||
|
|
||||||
FunctionInfo* symbol_info() const { return symbol_info_; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
FunctionInfo* symbol_info_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace runtime
|
} // namespace runtime
|
||||||
} // namespace alloy
|
} // namespace alloy
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,19 @@ void SymbolInfo::set_name(const char* name) {
|
||||||
FunctionInfo::FunctionInfo(Module* module, uint64_t address) :
|
FunctionInfo::FunctionInfo(Module* module, uint64_t address) :
|
||||||
end_address_(0), behavior_(BEHAVIOR_DEFAULT), function_(0),
|
end_address_(0), behavior_(BEHAVIOR_DEFAULT), function_(0),
|
||||||
SymbolInfo(SymbolInfo::TYPE_FUNCTION, module, address) {
|
SymbolInfo(SymbolInfo::TYPE_FUNCTION, module, address) {
|
||||||
|
xe_zero_struct(&extern_info_, sizeof(extern_info_));
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionInfo::~FunctionInfo() {
|
FunctionInfo::~FunctionInfo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FunctionInfo::SetupExtern(ExternHandler handler, void* arg0, void* arg1) {
|
||||||
|
behavior_ = BEHAVIOR_EXTERN;
|
||||||
|
extern_info_.handler = handler;
|
||||||
|
extern_info_.arg0 = arg0;
|
||||||
|
extern_info_.arg1 = arg1;
|
||||||
|
}
|
||||||
|
|
||||||
VariableInfo::VariableInfo(Module* module, uint64_t address) :
|
VariableInfo::VariableInfo(Module* module, uint64_t address) :
|
||||||
SymbolInfo(SymbolInfo::TYPE_VARIABLE, module, address) {
|
SymbolInfo(SymbolInfo::TYPE_VARIABLE, module, address) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,7 @@ public:
|
||||||
BEHAVIOR_PROLOG,
|
BEHAVIOR_PROLOG,
|
||||||
BEHAVIOR_EPILOG,
|
BEHAVIOR_EPILOG,
|
||||||
BEHAVIOR_EPILOG_RETURN,
|
BEHAVIOR_EPILOG_RETURN,
|
||||||
|
BEHAVIOR_EXTERN,
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -79,10 +80,21 @@ public:
|
||||||
Function* function() const { return function_; }
|
Function* function() const { return function_; }
|
||||||
void set_function(Function* value) { function_ = value; }
|
void set_function(Function* value) { function_ = value; }
|
||||||
|
|
||||||
|
typedef void(*ExternHandler)(void* context, void* arg0, void* arg1);
|
||||||
|
void SetupExtern(ExternHandler handler, void* arg0, void* arg1);
|
||||||
|
ExternHandler extern_handler() const { return extern_info_.handler; }
|
||||||
|
void* extern_arg0() const { return extern_info_.arg0; }
|
||||||
|
void* extern_arg1() const { return extern_info_.arg1; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64_t end_address_;
|
uint64_t end_address_;
|
||||||
Behavior behavior_;
|
Behavior behavior_;
|
||||||
Function* function_;
|
Function* function_;
|
||||||
|
struct {
|
||||||
|
ExternHandler handler;
|
||||||
|
void* arg0;
|
||||||
|
void* arg1;
|
||||||
|
} extern_info_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VariableInfo : public SymbolInfo {
|
class VariableInfo : public SymbolInfo {
|
||||||
|
|
|
@ -648,7 +648,6 @@ json_t* Processor::DumpModule(XexModule* module, bool& succeeded) {
|
||||||
json_object_set_new(import_library_json, "imports", imports_json);
|
json_object_set_new(import_library_json, "imports", imports_json);
|
||||||
|
|
||||||
json_array_append_new(library_imports_json, import_library_json);
|
json_array_append_new(library_imports_json, import_library_json);
|
||||||
xe_free(import_infos);
|
|
||||||
}
|
}
|
||||||
json_object_set_new(module_json, "libraryImports", library_imports_json);
|
json_object_set_new(module_json, "libraryImports", library_imports_json);
|
||||||
|
|
||||||
|
|
|
@ -135,14 +135,12 @@ int XexModule::SetupLibraryImports(const xe_xex2_import_library_t* library) {
|
||||||
if (kernel_export->type == KernelExport::Function) {
|
if (kernel_export->type == KernelExport::Function) {
|
||||||
// Not exactly sure what this should be...
|
// Not exactly sure what this should be...
|
||||||
if (info->thunk_address) {
|
if (info->thunk_address) {
|
||||||
// slot = XESWAP32BE(info->thunk_address);
|
*slot = XESWAP32BE(info->thunk_address);
|
||||||
// Setting this breaks other emu code that relies on it not being
|
|
||||||
// modified. Not sure what to do.
|
|
||||||
} else {
|
} else {
|
||||||
// TODO(benvanik): find out what import variables are.
|
// TODO(benvanik): find out what import variables are.
|
||||||
XELOGW("kernel import variable not defined %.8X %s",
|
XELOGW("kernel import variable not defined %.8X %s",
|
||||||
info->value_address, kernel_export->name);
|
info->value_address, kernel_export->name);
|
||||||
//*slot = XESWAP32BE(0xF00DF00D);
|
*slot = XESWAP32BE(0xF00DF00D);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (kernel_export->is_implemented) {
|
if (kernel_export->is_implemented) {
|
||||||
|
@ -165,39 +163,45 @@ int XexModule::SetupLibraryImports(const xe_xex2_import_library_t* library) {
|
||||||
info->ordinal);
|
info->ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionInfo* fn_info;
|
// On load we have something like this in memory:
|
||||||
DeclareFunction(info->thunk_address, &fn_info);
|
// li r3, 0
|
||||||
fn_info->set_end_address(info->thunk_address + 16 - 4);
|
// li r4, 0x1F5
|
||||||
//fn->type = FunctionSymbol::Kernel;
|
// mtspr CTR, r11
|
||||||
//fn->kernel_export = kernel_export;
|
// bctr
|
||||||
fn_info->set_name(name);
|
// Real consoles rewrite this with some code that sets r11.
|
||||||
fn_info->set_status(SymbolInfo::STATUS_DECLARED);
|
// If we did that we'd still have to put a thunk somewhere and do the
|
||||||
|
// dynamic lookup. Instead, we rewrite it to use syscalls, as they
|
||||||
|
// aren't used on the 360. Alloy backends can either take the syscall
|
||||||
|
// or do something smarter.
|
||||||
|
// sc
|
||||||
|
// blr
|
||||||
|
// nop
|
||||||
|
// nop
|
||||||
|
uint8_t* p = memory()->Translate(info->thunk_address);
|
||||||
|
XESETUINT32BE(p + 0x0, 0x44000002);
|
||||||
|
XESETUINT32BE(p + 0x4, 0x4E800020);
|
||||||
|
XESETUINT32BE(p + 0x8, 0x60000000);
|
||||||
|
XESETUINT32BE(p + 0xC, 0x60000000);
|
||||||
|
|
||||||
ExternFunction::Handler handler = 0;
|
FunctionInfo::ExternHandler handler = 0;
|
||||||
void* handler_data = 0;
|
void* handler_data = 0;
|
||||||
if (kernel_export) {
|
if (kernel_export) {
|
||||||
handler = (ExternFunction::Handler)kernel_export->function_data.shim;
|
handler = (FunctionInfo::ExternHandler)kernel_export->function_data.shim;
|
||||||
handler_data = kernel_export->function_data.shim_data;
|
handler_data = kernel_export->function_data.shim_data;
|
||||||
} else {
|
} else {
|
||||||
handler = (ExternFunction::Handler)UndefinedImport;
|
handler = (FunctionInfo::ExternHandler)UndefinedImport;
|
||||||
handler_data = this;
|
handler_data = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
DefineFunction(fn_info);
|
FunctionInfo* fn_info;
|
||||||
auto fn = new ExternFunction(
|
DeclareFunction(info->thunk_address, &fn_info);
|
||||||
info->thunk_address,
|
fn_info->set_end_address(info->thunk_address + 16 - 4);
|
||||||
handler,
|
fn_info->set_name(name);
|
||||||
handler_data,
|
fn_info->SetupExtern(handler, handler_data, NULL);
|
||||||
NULL);
|
fn_info->set_status(SymbolInfo::STATUS_DECLARED);
|
||||||
if (kernel_export) {
|
|
||||||
fn->set_name(kernel_export->name);
|
|
||||||
}
|
|
||||||
fn_info->set_function(fn);
|
|
||||||
fn_info->set_status(SymbolInfo::STATUS_DEFINED);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xe_free(import_infos);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,28 @@ void ExportResolver::RegisterTable(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t ExportResolver::GetLibraryOrdinal(const char* library_name) {
|
||||||
|
uint16_t n = 0;
|
||||||
|
for (auto it = tables_.begin(); it != tables_.end(); ++it, n++) {
|
||||||
|
if (!xestrcmpa(library_name, it->name)) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
KernelExport* ExportResolver::GetExportByOrdinal(
|
||||||
|
const uint16_t library_ordinal, const uint32_t ordinal) {
|
||||||
|
auto& table = tables_[library_ordinal];
|
||||||
|
// TODO(benvanik): binary search?
|
||||||
|
for (size_t n = 0; n < table.count; n++) {
|
||||||
|
if (table.exports[n].ordinal == ordinal) {
|
||||||
|
return &table.exports[n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
KernelExport* ExportResolver::GetExportByOrdinal(const char* library_name,
|
KernelExport* ExportResolver::GetExportByOrdinal(const char* library_name,
|
||||||
const uint32_t ordinal) {
|
const uint32_t ordinal) {
|
||||||
for (std::vector<ExportTable>::iterator it = tables_.begin();
|
for (std::vector<ExportTable>::iterator it = tables_.begin();
|
||||||
|
|
|
@ -68,6 +68,10 @@ public:
|
||||||
void RegisterTable(const char* library_name, KernelExport* exports,
|
void RegisterTable(const char* library_name, KernelExport* exports,
|
||||||
const size_t count);
|
const size_t count);
|
||||||
|
|
||||||
|
uint16_t GetLibraryOrdinal(const char* library_name);
|
||||||
|
|
||||||
|
KernelExport* GetExportByOrdinal(const uint16_t library_ordinal,
|
||||||
|
const uint32_t ordinal);
|
||||||
KernelExport* GetExportByOrdinal(const char* library_name,
|
KernelExport* GetExportByOrdinal(const char* library_name,
|
||||||
const uint32_t ordinal);
|
const uint32_t ordinal);
|
||||||
KernelExport* GetExportByName(const char* library_name, const char* name);
|
KernelExport* GetExportByName(const char* library_name, const char* name);
|
||||||
|
|
|
@ -345,8 +345,6 @@ void XUserModule::Dump() {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xe_free(import_infos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
|
@ -29,6 +29,11 @@ typedef struct xe_xex2 {
|
||||||
xe_xex2_header_t header;
|
xe_xex2_header_t header;
|
||||||
|
|
||||||
std::vector<PESection*>* sections;
|
std::vector<PESection*>* sections;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
size_t count;
|
||||||
|
xe_xex2_import_info_t* infos;
|
||||||
|
} library_imports[16];
|
||||||
} xe_xex2_t;
|
} xe_xex2_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,6 +44,8 @@ int xe_xex2_read_image(xe_xex2_ref xex,
|
||||||
const uint8_t *xex_addr, const size_t xex_length,
|
const uint8_t *xex_addr, const size_t xex_length,
|
||||||
Memory* memory);
|
Memory* memory);
|
||||||
int xe_xex2_load_pe(xe_xex2_ref xex);
|
int xe_xex2_load_pe(xe_xex2_ref xex);
|
||||||
|
int xe_xex2_find_import_infos(xe_xex2_ref xex,
|
||||||
|
const xe_xex2_import_library_t* library);
|
||||||
|
|
||||||
|
|
||||||
xe_xex2_ref xe_xex2_load(Memory* memory,
|
xe_xex2_ref xe_xex2_load(Memory* memory,
|
||||||
|
@ -58,6 +65,11 @@ xe_xex2_ref xe_xex2_load(Memory* memory,
|
||||||
|
|
||||||
XEEXPECTZERO(xe_xex2_load_pe(xex));
|
XEEXPECTZERO(xe_xex2_load_pe(xex));
|
||||||
|
|
||||||
|
for (size_t n = 0; n < xex->header.import_library_count; n++) {
|
||||||
|
auto library = &xex->header.import_libraries[n];
|
||||||
|
XEEXPECTZERO(xe_xex2_find_import_infos(xex, library));
|
||||||
|
}
|
||||||
|
|
||||||
return xex;
|
return xex;
|
||||||
|
|
||||||
XECLEANUP:
|
XECLEANUP:
|
||||||
|
@ -894,12 +906,10 @@ const PESection* xe_xex2_get_pe_section(xe_xex2_ref xex, const char* name) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int xe_xex2_get_import_infos(xe_xex2_ref xex,
|
int xe_xex2_find_import_infos(xe_xex2_ref xex,
|
||||||
const xe_xex2_import_library_t *library,
|
const xe_xex2_import_library_t *library) {
|
||||||
xe_xex2_import_info_t **out_import_infos,
|
|
||||||
size_t *out_import_info_count) {
|
|
||||||
uint8_t* mem = xex->memory->membase();
|
uint8_t* mem = xex->memory->membase();
|
||||||
const xe_xex2_header_t *header = xe_xex2_get_header(xex);
|
auto header = xe_xex2_get_header(xex);
|
||||||
|
|
||||||
// Find library index for verification.
|
// Find library index for verification.
|
||||||
size_t library_index = -1;
|
size_t library_index = -1;
|
||||||
|
@ -970,13 +980,34 @@ int xe_xex2_get_import_infos(xe_xex2_ref xex,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_import_info_count = info_count;
|
xex->library_imports[library_index].count = info_count;
|
||||||
*out_import_infos = infos;
|
xex->library_imports[library_index].infos = infos;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
XECLEANUP:
|
XECLEANUP:
|
||||||
xe_free(infos);
|
xe_free(infos);
|
||||||
*out_import_info_count = 0;
|
|
||||||
*out_import_infos = NULL;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int xe_xex2_get_import_infos(xe_xex2_ref xex,
|
||||||
|
const xe_xex2_import_library_t *library,
|
||||||
|
xe_xex2_import_info_t **out_import_infos,
|
||||||
|
size_t *out_import_info_count) {
|
||||||
|
auto header = xe_xex2_get_header(xex);
|
||||||
|
|
||||||
|
// Find library index for verification.
|
||||||
|
size_t library_index = -1;
|
||||||
|
for (size_t n = 0; n < header->import_library_count; n++) {
|
||||||
|
if (&header->import_libraries[n] == library) {
|
||||||
|
library_index = n;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (library_index == (size_t)-1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_import_info_count = xex->library_imports[library_index].count;
|
||||||
|
*out_import_infos = xex->library_imports[library_index].infos;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue