write.c
7.67 KB
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
/*==============================================================================
Module: write.c
$Revision: 1.1.1.2 $
$Date: 2002/10/29 08:07:15 $
$Author: blythe $
$Source: /root/leakn64/depot/rf/sw/n64os20l/tools/gcord/com/write.c,v $
==============================================================================*/
#include <libelf.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <malloc.h>
#include "global.h"
#include "option.h"
#include "update.h"
/*------------------------------------------------------------------------------
update the program entry point
------------------------------------------------------------------------------*/
void update_elf_header(void)
{
if(IS_32BIT())
update_elf_header32();
else
update_elf_header64();
}
/*------------------------------------------------------------------------------
update .dynamic section.
------------------------------------------------------------------------------*/
void update_dynamic(void)
{
if(IS_32BIT())
update_dynamic32();
else
update_dynamic64();
}
/*------------------------------------------------------------------------------
update .got section
------------------------------------------------------------------------------*/
void update_got(void)
{
if(IS_32BIT())
update_got32();
else
update_got64();
}
/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
void update_reldyn(void)
{
if(IS_32BIT())
update_reldyn32();
else
update_reldyn64();
}
/*------------------------------------------------------------------------------
update .dynsym section.
------------------------------------------------------------------------------*/
void update_dynsym(void)
{
if(IS_32BIT())
update_dynsym32();
else
update_dynsym64();
}
/*------------------------------------------------------------------------------
update .symtab section.
------------------------------------------------------------------------------*/
void update_symtab(void)
{
if(IS_32BIT())
update_symtab32();
else
update_symtab64();
}
/*------------------------------------------------------------------------------
Expand .text section.
------------------------------------------------------------------------------*/
void expand_text(void)
{
if(IS_32BIT())
expand_text32();
else
expand_text64();
}
/*------------------------------------------------------------------------------
1. Process events section.
2. Update contents in events section.
------------------------------------------------------------------------------*/
void update_events(void)
{
}
/*------------------------------------------------------------------------------
The runtime procedure table is used by ADA,
COBOL and PL/1 for exception handling. This
table is tacked on the end of the .data section
and is pointed to by the symbols:
_procedure_table - table location
_procedure_table_size - number of table entries
if the value of _procedure_table is zero, the
table will be in a non-loadable part of the object file
(currently hidden not in a section) and its file offset
is stored in the program header.
------------------------------------------------------------------------------*/
void update_rpt(void)
{
}
/*------------------------------------------------------------------------------
Update addresses in jump instruction.
This should only be needed for non-shared, as shared program should use
jalr t9.
------------------------------------------------------------------------------*/
void update_jump(MIPS_Inst inst, Addr old_address)
{
Addr target;
Addr new_target;
Addr new_address;
target = inst.j_format.target <<2;
target |= (old_address + SIZE_INST) & 0xf0000000;
/* TO_DO: target may jump over 1G byte range */
if (IN_TEXT(target))
{
new_target = NEW_ADDR(target);
new_address = NEW_ADDR(old_address);
GET_NEWTEXT_BY_ADDR(new_address).j_format.target = new_target >> 2;
}
else if (IN_BROAD_TEXT(target) && target > bin.text_hi)
{
new_target = target + bin.text_expand_offset;
new_address = NEW_ADDR(old_address);
GET_NEWTEXT_BY_ADDR(new_address).j_format.target = new_target >> 2;
}
else
{
warning("jump target %#llx not in .text or .init", (Uint64) target);
}
if (option.debug)
dump("jump at %#llx changed from %#llx to %#llx",
(Uint64) old_address, (Uint64) target, (Uint64) new_target);
return;
}
/*------------------------------------------------------------------------------
Update the branch offset in branch instructions.
------------------------------------------------------------------------------*/
void update_one_branch(MIPS_Inst inst, Addr old_address)
{
Addr new_address;
short offset; /* branch offset */
Sint32 new_offset;
Addr target; /* target address */
Addr new_target; /* target address */
new_address = NEW_ADDR(old_address);
offset = inst.i_format.simmediate <<2;
target = old_address + offset + SIZE_INST;
new_target = NEW_ADDR(target);
new_offset = (Sint32) (new_target - new_address - SIZE_INST) >>2;
if(new_offset > 0x7fff || new_offset < -0x8000)
error("branch new offset %#x out of range", new_offset);
GET_NEWTEXT_BY_ADDR(new_address).i_format.simmediate = (short) new_offset;
}
/*------------------------------------------------------------------------------
update branch/jump offset
This looks at the old text and modifies the corresponding new instructions.
------------------------------------------------------------------------------*/
void update_branch_offset(void)
{
int i;
MIPS_Inst inst;
unsigned int * instructionAddress = (unsigned int *)bin.text_lo;
if ( option.debug )
printf( "updating jumps\n" );
for(i = 0; i < bin.n_instructions; i++, ++instructionAddress)
{
/* Since we have mixed code and data, check for code here */
if ( !get_proc_by_addr( instructionAddress ) )
continue; /* assume it is not code */
inst = bin.text[i];
switch (inst.i_format.opcode)
{
case j_op:
case jal_op:
update_jump(inst, bin.text_lo + i*SIZE_INST);
break;
case spec_op:
switch (inst.r_format.func)
{
case jalr_op:
case jr_op:
break;
}
break;
case bcond_op:
switch (inst.i_format.rt)
{
case bltz_op:
case bgez_op:
case bltzl_op:
case bgezl_op:
case bltzal_op:
case bgezal_op:
case bltzall_op:
case bgezall_op:
update_one_branch(inst, bin.text_lo + i*SIZE_INST);
}
break;
case beq_op:
case bne_op:
case blez_op:
case bgtz_op:
case beql_op:
case bnel_op:
case blezl_op:
case bgtzl_op:
update_one_branch(inst, bin.text_lo + i*SIZE_INST);
break;
case cop0_op:
case cop1_op:
case cop2_op:
if (inst.i_format.rs == bc_op)
{
update_one_branch(inst, bin.text_lo + i*SIZE_INST);
}
break;
default:
break;
}
}
}
/*------------------------------------------------------------------------------
write out the binary
------------------------------------------------------------------------------*/
void write_it(void)
{
int size;
size = elf_update(bin.new_elf, ELF_C_WRITE);
if (size == -1)
print_elf_error();
elf_end(bin.new_elf);
}