[x64] Fix up unwind info for emitted functions.

- [x64] Track size of code within emitted functions (prolog, body, epilog).
- [x64] Don't use hardcoded prolog size in generated unwind info.
- [x64] Update URLs to MSDN documentation on UNWIND_INFO/UNWIND_CODE.
This commit is contained in:
gibbed
2019-08-23 05:34:19 -05:00
committed by Rick Gibbed
parent 918a7d4365
commit 0dc4a13db3
6 changed files with 166 additions and 54 deletions

View File

@@ -102,14 +102,14 @@ bool X64Emitter::Emit(GuestFunction* function, HIRBuilder* builder,
source_map_arena_.Reset();
// Fill the generator with code.
size_t stack_size = 0;
if (!Emit(builder, &stack_size)) {
EmitFunctionInfo func_info = {};
if (!Emit(builder, func_info)) {
return false;
}
// Copy the final code to the cache and relocate it.
*out_code_size = getSize();
*out_code_address = Emplace(stack_size, function);
*out_code_address = Emplace(func_info, function);
// Stash source map.
source_map_arena_.CloneContents(out_source_map);
@@ -117,18 +117,20 @@ bool X64Emitter::Emit(GuestFunction* function, HIRBuilder* builder,
return true;
}
void* X64Emitter::Emplace(size_t stack_size, GuestFunction* function) {
void* X64Emitter::Emplace(const EmitFunctionInfo& func_info,
GuestFunction* function) {
// To avoid changing xbyak, we do a switcharoo here.
// top_ points to the Xbyak buffer, and since we are in AutoGrow mode
// it has pending relocations. We copy the top_ to our buffer, swap the
// pointer, relocate, then return the original scratch pointer for use.
uint8_t* old_address = top_;
void* new_address;
assert_true(func_info.code_size.total == size_);
if (function) {
new_address = code_cache_->PlaceGuestCode(function->address(), top_, size_,
stack_size, function);
new_address = code_cache_->PlaceGuestCode(function->address(), top_,
func_info, function);
} else {
new_address = code_cache_->PlaceHostCode(0, top_, size_, stack_size);
new_address = code_cache_->PlaceHostCode(0, top_, func_info);
}
top_ = reinterpret_cast<uint8_t*>(new_address);
ready();
@@ -137,7 +139,7 @@ void* X64Emitter::Emplace(size_t stack_size, GuestFunction* function) {
return new_address;
}
bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
bool X64Emitter::Emit(HIRBuilder* builder, EmitFunctionInfo& func_info) {
Xbyak::Label epilog_label;
epilog_label_ = &epilog_label;
@@ -159,6 +161,15 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
stack_offset -= StackLayout::GUEST_STACK_SIZE;
stack_offset = xe::align(stack_offset, static_cast<size_t>(16));
struct _code_offsets {
size_t prolog;
size_t body;
size_t epilog;
size_t tail;
} code_offsets = {};
code_offsets.prolog = getSize();
// Function prolog.
// Must be 16b aligned.
// Windows is very strict about the form of this and the epilog:
@@ -168,7 +179,7 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
// Adding or changing anything here must be matched!
const size_t stack_size = StackLayout::GUEST_STACK_SIZE + stack_offset;
assert_true((stack_size + 8) % 16 == 0);
*out_stack_size = stack_size;
func_info.stack_size = stack_size;
stack_size_ = stack_size;
sub(rsp, (uint32_t)stack_size);
@@ -208,6 +219,8 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
mov(GetMembaseReg(),
qword[GetContextReg() + offsetof(ppc::PPCContext, virtual_membase)]);
code_offsets.body = getSize();
// Body.
auto block = builder->first_block();
while (block) {
@@ -236,6 +249,8 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
block = block->next;
}
code_offsets.epilog = getSize();
// Function epilog.
L(epilog_label);
epilog_label_ = nullptr;
@@ -244,6 +259,8 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
add(rsp, (uint32_t)stack_size);
ret();
code_offsets.tail = getSize();
if (cvars::emit_source_annotations) {
nop();
nop();
@@ -252,6 +269,13 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
nop();
}
assert_zero(code_offsets.prolog);
func_info.code_size.total = getSize();
func_info.code_size.prolog = code_offsets.body - code_offsets.prolog;
func_info.code_size.body = code_offsets.epilog - code_offsets.body;
func_info.code_size.epilog = code_offsets.tail - code_offsets.epilog;
func_info.code_size.tail = getSize() - code_offsets.tail;
return true;
}