-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy patharm6_rt.c
143 lines (132 loc) · 4.24 KB
/
arm6_rt.c
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
142
#include "config.h"
#include <string.h>
#include "dill.h"
#include "dill_internal.h"
#include "sys/mman.h"
#ifdef HAVE_MEMORY_H
#include "memory.h"
#endif
#include "arm6.h"
#include <string.h>
extern int arm6_hidden_modi(int a, int b)
{ return a % b; }
extern long arm6_hidden_mod(long a, long b)
{ return a % b; }
extern unsigned long arm6_hidden_umod(unsigned long a, unsigned long b)
{ return a % b; }
extern unsigned int arm6_hidden_umodi(unsigned int a, unsigned int b)
{ return a % b; }
extern double arm6_hidden_ultod(unsigned long a)
{ return (double) a; }
extern float arm6_hidden_ultof(unsigned long a)
{ return (float) a; }
extern unsigned long arm6_hidden_dtoul(double a)
{ return (unsigned long) a; }
extern unsigned int arm6_hidden_dtou(double a)
{ return (unsigned int) a; }
extern unsigned long arm6_hidden_ftoul(float a)
{ return (unsigned long) a; }
extern unsigned int arm6_hidden_ftou(float a)
{ return (unsigned int) a; }
extern unsigned long arm6_hidden_udiv(unsigned long a, unsigned long b)
{ return a / b; }
extern long arm6_hidden_div(long a, long b)
{ return a / b; }
#define COND(x) ((unsigned)((x)&0xf) << 28)
#define CLASS(x) (((x)&0x7) << 25)
static xfer_entry arm6_xfer_recs[] = {
{"arm6_hidden_modi", arm6_hidden_modi},
{"arm6_hidden_mod", arm6_hidden_mod},
{"arm6_hidden_umod", arm6_hidden_umod},
{"arm6_hidden_umodi", arm6_hidden_umodi},
{"arm6_hidden_ultod", arm6_hidden_ultod},
{"arm6_hidden_ultof", arm6_hidden_ultof},
{"arm6_hidden_dtoul", arm6_hidden_dtoul},
{"arm6_hidden_dtou", arm6_hidden_dtou},
{"arm6_hidden_ftoul", arm6_hidden_ftoul},
{"arm6_hidden_ftou", arm6_hidden_ftou},
{"arm6_hidden_udiv", arm6_hidden_udiv},
{"arm6_hidden_div", arm6_hidden_div},
{(char*)0, (void*)0}};
static void
arm6_rt_set_PLT_locs(call_t* t, dill_pkg pkg)
{
/*
* Must set mach_info with PLT entry location.
* One entry per call, stacked at the end of the code block
*/
int i;
int PLT_offset = pkg->code_size - 3 * 4; /* 3 insn per PLT entry */
for (i=t->call_count-1; i>=0; i--) {
t->call_locs[i].mach_info = (void*) (intptr_t)PLT_offset;
PLT_offset -= 3 * 4;
}
}
extern void
arm6_rt_call_link(char *code, call_t *t)
{
int i;
for(i=0; i< t->call_count; i++) {
int *call_addr = (int*) ((unsigned long)code +
t->call_locs[i].loc);
if (t->call_locs[i].mach_info == NULL) {
/* no PLT */
int call_offset = (unsigned long)t->call_locs[i].xfer_addr -
(unsigned long)call_addr;
int thumb_target = (((unsigned long)t->call_locs[i].xfer_addr & 0x1) == 0x1);
int bit1;
/* compensate for arm PC lookahead */
call_offset = call_offset - 8;
/* div addr diff by 4 for arm offset value */
bit1 = (call_offset & 0x2) >> 1;
call_offset = call_offset >> 2;
*call_addr &= 0xff000000;
*call_addr |= (call_offset & 0xffffff);
if (thumb_target) {
*call_addr &= 0x00ffffff; /* kill top bit */
*call_addr |= (COND(0xf)|CLASS(5)|bit1<<24); /* blx */
}
} else {
/* call through PLT */
unsigned long PLT_addr = (unsigned long)code +
(unsigned long)t->call_locs[i].mach_info;
int call_offset = PLT_addr - (unsigned long)call_addr;
/* compensate for arm PC lookahead */
call_offset = call_offset - 8;
call_offset = call_offset >> 2;
*call_addr &= 0xff000000;
*call_addr |= (call_offset & 0x00ffffff);
PLT_addr += 8;
*(unsigned long*)PLT_addr = (unsigned long)t->call_locs[i].xfer_addr;
}
}
}
#ifndef CLEAR_CACHE_DEFINED
extern void __clear_cache(void *, void *);
#endif
static void
arm6_flush(void *base, void *limit)
{
#if defined(HOST_ARM6) || defined(HOST_ARM7)
__clear_cache(base, limit);
#endif
}
extern char *
arm6_package_stitch(char *code, call_t *t, dill_pkg pkg)
{
char *tmp = code;
dill_lookup_xfer_addrs(t, &arm6_xfer_recs[0]);
arm6_rt_set_PLT_locs(t, pkg);
#ifdef USE_MMAP_CODE_SEG
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
tmp = (void*)mmap(0, pkg->code_size,
PROT_EXEC | PROT_READ | PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
memcpy(tmp, code, pkg->code_size);
#endif
arm6_rt_call_link(tmp, t);
arm6_flush(code, tmp+pkg->code_size);
return tmp + pkg->entry_offset;
}