aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/stack-frame.c
blob: 25680e5c34ae9ef421dd984bebc12915555250dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 * Copyright (C) 2006-2008  Pekka Enberg
 *
 * This file is released under the GPL version 2 with the following
 * clarification and special exception:
 *
 *     Linking this library statically or dynamically with other modules is
 *     making a combined work based on this library. Thus, the terms and
 *     conditions of the GNU General Public License cover the whole
 *     combination.
 *
 *     As a special exception, the copyright holders of this library give you
 *     permission to link this library with independent modules to produce an
 *     executable, regardless of the license terms of these independent
 *     modules, and to copy and distribute the resulting executable under terms
 *     of your choice, provided that you also meet, for each linked independent
 *     module, the terms and conditions of the license of that module. An
 *     independent module is a module which is not derived from or based on
 *     this library. If you modify this library, you may extend this exception
 *     to your version of the library, but you are not obligated to do so. If
 *     you do not wish to do so, delete this exception statement from your
 *     version.
 *
 * Please refer to the file LICENSE for details.
 */

#include <assert.h>
#include <stdlib.h>

#include "jit/compilation-unit.h"
#include "jit/expression.h"
#include "jit/compiler.h"
#include "jit/text.h"

#include "vm/stack-trace.h"
#include "vm/method.h"
#include "vm/vm.h"

#include "arch/stack-frame.h"

/*
 * The three callee-saved registers are unconditionally stored on the stack
 * after EIP and EBP (see emit_prolog() for details). Therefore, there are five
 * 32-bit stack slots before the first argument to a function as illustrated by
 * the following diagram:
 *
 *     :              :  ^
 *     :              :  |  Higher memory addresses
 *     +--------------+  |
 *     |    Arg n     |
 *     :     ...      :
 *     |    Arg 1     | <-- Start offset of arguments
 *     |   Old EIP    |
 *     |     EDI      |
 *     |     ESI      |
 *     |     EBX      |
 *     |   Old EBP    | <-- New EBP
 *     |   Local 1    |
 *     :     ...      :
 *     |   Local m    :
 *     +--------------+
 */

#define ARGS_START_OFFSET offsetof(struct jit_stack_frame, args)

static unsigned long __index_to_offset(unsigned long index)
{
	return index * sizeof(unsigned long);
}

static unsigned long
index_to_offset(unsigned long idx, int size, unsigned long nr_args)
{
	if (idx < nr_args)
		return ARGS_START_OFFSET + __index_to_offset(idx);

	return 0UL - __index_to_offset(idx - nr_args + size);
}

unsigned long frame_local_offset(struct vm_method *method,
				 struct expression *local)
{
	unsigned long idx, nr_args;

	idx = local->local_index;
	nr_args = method->args_count;

	return index_to_offset(idx, vm_type_slot_size(local->vm_type), nr_args);
}

unsigned long slot_offset(struct stack_slot *slot)
{
	struct stack_frame *frame = slot->parent;

	return index_to_offset(slot->index, 1, frame->nr_args);
}

unsigned long slot_offset_64(struct stack_slot *slot)
{
	struct stack_frame *frame = slot->parent;

	return index_to_offset(slot->index, 2, frame->nr_args);
}

unsigned long frame_locals_size(struct stack_frame *frame)
{
	unsigned long nr_locals;

	assert(frame->nr_local_slots >= frame->nr_args);

	nr_locals = frame->nr_local_slots - frame->nr_args;
	return __index_to_offset(nr_locals + frame->nr_spill_slots);
}

/*
 * Returns total offset to subtract from ESP to reserve space for locals.
 */
unsigned long cu_frame_locals_offset(struct compilation_unit *cu)
{
	unsigned long frame_size = frame_locals_size(cu->stack_frame);
	return frame_size * sizeof(unsigned long);
}

/*
 * Checks whether given native function was called from jit trampoline
 * code. It checks whether return address points after a relative call
 * to jit_magic_trampoline, which is typical for trampolines.
 */
bool called_from_jit_trampoline(struct native_stack_frame *frame)
{
	void *call_target;
	void **call_site;

	call_site = (void *)frame->return_address - sizeof(void *);
	if (!is_jit_text(call_site))
		return false;

	call_target = *call_site + frame->return_address;

	return call_target == &jit_magic_trampoline;
}