12 |
#define vmaptr(x) ((void*)(unsigned long)(x)) |
#define vmaptr(x) ((void*)(unsigned long)(x)) |
13 |
#define ptrvma(x) ((bfd_vma)(unsigned long)(x)) |
#define ptrvma(x) ((bfd_vma)(unsigned long)(x)) |
14 |
|
|
15 |
/* These subroutines alter the relocation code |
static void * |
16 |
* and generate the GOT table that BFD |
xballoc(bfd *abfd, size_t n) { |
|
* does not handle properly. |
|
|
*/ |
|
17 |
|
|
18 |
/* mipself_old_{lo16,hi16}_reloc -- |
void *ans = (void*)bfd_alloc(abfd, n); |
19 |
pointer to old reloc functions */ |
|
20 |
|
if (!ans) |
21 |
|
FEerror("bfd error: ~S", 1 , bfd_errmsg(bfd_error_no_memory)); |
22 |
|
return ans; |
23 |
|
|
|
static void * |
|
|
xballoc(bfd *abfd, size_t n) |
|
|
{ |
|
|
void *ans = (void*)bfd_alloc(abfd, n); |
|
|
if (!ans) |
|
|
FEerror("bfd error: ~S", 1 , bfd_errmsg(bfd_error_no_memory)); |
|
|
return ans; |
|
24 |
} |
} |
25 |
|
|
26 |
|
|
46 |
|
|
47 |
/* mipself_gpdisp_hiaddr, mipself_gpdisp_value -- |
/* mipself_gpdisp_hiaddr, mipself_gpdisp_value -- |
48 |
static variables for setting gp_disp */ |
static variables for setting gp_disp */ |
|
|
|
49 |
static bfd_vma mipself_gpdisp_value = 0; |
static bfd_vma mipself_gpdisp_value = 0; |
50 |
static bfd_vma mipself_gpdisp_hiaddr = 0; |
static bfd_vma mipself_gpdisp_hiaddr = 0; |
51 |
|
|
52 |
|
|
53 |
/* mipself_new_{lo16,hi16,gprel32}_reloc -- |
/* mipself_new_{lo16,hi16,gprel32}_reloc -- |
54 |
new reloc functions patching the bogus BFD functions */ |
new reloc functions patching the bogus BFD functions */ |
|
|
|
55 |
static bfd_reloc_status_type |
static bfd_reloc_status_type |
56 |
mipself_new_hi16_reloc (bfd *abfd, |
mipself_new_hi16_reloc (bfd *abfd, |
57 |
arelent *reloc_entry, |
arelent *reloc_entry, |
59 |
PTR data, |
PTR data, |
60 |
asection *input_section, |
asection *input_section, |
61 |
bfd *output_bfd, |
bfd *output_bfd, |
62 |
char **error_message) |
char **error_message) { |
63 |
{ |
|
64 |
if (output_bfd) |
if (output_bfd) |
65 |
return bfd_reloc_notsupported; |
return bfd_reloc_notsupported; |
66 |
|
|
67 |
/* Test if symbol is '_gp_disp' because it changes everything */ |
/* Test if symbol is '_gp_disp' because it changes everything */ |
68 |
if (!strcmp(symbol->name, "_gp_disp")) |
if (!strcmp(symbol->name, "_gp_disp")) { |
69 |
{ |
|
70 |
mipself_gpdisp_hiaddr = ptrvma(data) + reloc_entry->address; |
mipself_gpdisp_hiaddr = ptrvma(data) + reloc_entry->address; |
71 |
mipself_gpdisp_value = symbol->section->vma + symbol->value; |
mipself_gpdisp_value = symbol->section->vma + symbol->value; |
72 |
/* Assume no addend for simplicity*/ |
|
73 |
if (reloc_entry->addend) |
/* Assume no addend for simplicity*/ |
74 |
return bfd_reloc_notsupported; |
if (reloc_entry->addend) |
75 |
return bfd_reloc_ok; |
return bfd_reloc_notsupported; |
76 |
} |
|
77 |
|
return bfd_reloc_ok; |
78 |
|
|
79 |
|
} |
80 |
/* Regular procedure */ |
/* Regular procedure */ |
81 |
return (*mipself_old_hi16_reloc)(abfd, reloc_entry, symbol, |
return (*mipself_old_hi16_reloc)(abfd, reloc_entry, symbol, |
82 |
data, input_section, |
data, input_section, |
90 |
PTR data, |
PTR data, |
91 |
asection *input_section, |
asection *input_section, |
92 |
bfd *output_bfd, |
bfd *output_bfd, |
93 |
char **error_message) |
char **error_message) { |
94 |
{ |
|
95 |
if (output_bfd) |
if (output_bfd) |
96 |
return bfd_reloc_notsupported; |
return bfd_reloc_notsupported; |
97 |
|
|
98 |
/* Test if symbol is '_gp_disp' because it changes everything */ |
/* Test if symbol is '_gp_disp' because it changes everything */ |
99 |
if(!strcmp(symbol->name, "_gp_disp")) |
|
100 |
{ |
if(!strcmp(symbol->name, "_gp_disp")) { |
101 |
int loinsn, hiinsn; |
|
102 |
bfd_vma loaddr = ptrvma(data) + reloc_entry->address; |
int loinsn, hiinsn; |
103 |
bfd_vma value = symbol->section->vma + symbol->value; |
|
104 |
assert(value == mipself_gpdisp_value); |
bfd_vma loaddr = ptrvma(data) + reloc_entry->address; |
105 |
/* Assume no addend for simplicity*/ |
bfd_vma value = symbol->section->vma + symbol->value; |
106 |
if (reloc_entry->addend) |
|
107 |
return bfd_reloc_notsupported; |
assert(value == mipself_gpdisp_value); |
108 |
/* Get instructions */ |
|
109 |
loinsn = bfd_get_32(abfd, (bfd_byte*)vmaptr(loaddr)); |
/* Assume no addend for simplicity*/ |
110 |
hiinsn = bfd_get_32(abfd, (bfd_byte*)vmaptr(mipself_gpdisp_hiaddr)); |
if (reloc_entry->addend) |
111 |
if ((loinsn & 0xffff) || (hiinsn & 0xffff)) |
return bfd_reloc_notsupported; |
112 |
return bfd_reloc_notsupported; |
|
113 |
/* Patch instructions (taking care of sign extension on the low 16 bits) */ |
/* Get instructions */ |
114 |
value = value - mipself_gpdisp_hiaddr; |
loinsn = bfd_get_32(abfd, (bfd_byte*)vmaptr(loaddr)); |
115 |
loinsn |= (value & 0xffff); |
hiinsn = bfd_get_32(abfd, (bfd_byte*)vmaptr(mipself_gpdisp_hiaddr)); |
116 |
value = (value>>16) + (loinsn&0x8000 ? 1 : 0); |
|
117 |
hiinsn |= (value & 0xffff); |
if ((loinsn & 0xffff) || (hiinsn & 0xffff)) |
118 |
bfd_put_32 (abfd, hiinsn, (bfd_byte*)vmaptr(mipself_gpdisp_hiaddr)); |
return bfd_reloc_notsupported; |
119 |
bfd_put_32 (abfd, loinsn, (bfd_byte*)vmaptr(loaddr)); |
/* Patch instructions (taking care of sign extension on the low 16 bits) */ |
120 |
return bfd_reloc_ok; |
|
121 |
} |
value = value - mipself_gpdisp_hiaddr; |
122 |
|
loinsn |= (value & 0xffff); |
123 |
|
|
124 |
|
value = (value>>16) + (loinsn&0x8000 ? 1 : 0); |
125 |
|
hiinsn |= (value & 0xffff); |
126 |
|
|
127 |
|
bfd_put_32 (abfd, hiinsn, (bfd_byte*)vmaptr(mipself_gpdisp_hiaddr)); |
128 |
|
bfd_put_32 (abfd, loinsn, (bfd_byte*)vmaptr(loaddr)); |
129 |
|
|
130 |
|
return bfd_reloc_ok; |
131 |
|
|
132 |
|
} |
133 |
/* Regular procedure */ |
/* Regular procedure */ |
134 |
return (*mipself_old_lo16_reloc)(abfd, reloc_entry, symbol, |
return (*mipself_old_lo16_reloc)(abfd, reloc_entry, symbol, |
135 |
data, input_section, |
data, input_section, |
143 |
PTR data, |
PTR data, |
144 |
asection *input_section, |
asection *input_section, |
145 |
bfd *output_bfd, |
bfd *output_bfd, |
146 |
char **error_message) |
char **error_message) { |
147 |
{ |
|
148 |
/* This should only happen with GPDISP symbol */ |
/* This should only happen with GPDISP symbol */ |
149 |
int insn; |
int insn; |
150 |
bfd_byte *addr; |
bfd_byte *addr; |
151 |
|
|
152 |
/* Plug GOT offset into low 16 bits of instruction */ |
/* Plug GOT offset into low 16 bits of instruction */ |
153 |
addr = (bfd_byte*)(data) + reloc_entry->address; |
addr = (bfd_byte*)(data) + reloc_entry->address; |
154 |
insn = bfd_get_32(abfd, addr); |
insn = bfd_get_32(abfd, addr); |
155 |
|
|
156 |
if (insn & 0x0000ffff) |
if (insn & 0x0000ffff) |
157 |
return bfd_reloc_notsupported; |
return bfd_reloc_notsupported; |
158 |
|
|
159 |
if (reloc_entry->addend != (reloc_entry->addend & 0x7fff)) |
if (reloc_entry->addend != (reloc_entry->addend & 0x7fff)) |
160 |
return bfd_reloc_notsupported; |
return bfd_reloc_notsupported; |
161 |
|
|
162 |
insn |= reloc_entry->addend; |
insn |= reloc_entry->addend; |
163 |
|
|
164 |
bfd_put_32(abfd, insn, addr); |
bfd_put_32(abfd, insn, addr); |
165 |
|
|
166 |
return bfd_reloc_ok; |
return bfd_reloc_ok; |
167 |
|
|
168 |
} |
} |
169 |
|
|
170 |
static bfd_reloc_status_type |
static bfd_reloc_status_type |
174 |
PTR data, |
PTR data, |
175 |
asection *input_section, |
asection *input_section, |
176 |
bfd *output_bfd, |
bfd *output_bfd, |
177 |
char **error_message) |
char **error_message) { |
178 |
{ |
|
179 |
int insn; |
int insn; |
180 |
bfd_byte *addr; |
bfd_byte *addr; |
181 |
|
|
182 |
/* If symbol is '_gp_disp' same as CALL16 */ |
/* If symbol is '_gp_disp' same as CALL16 */ |
183 |
if (!strcmp(symbol->name,"_gp_disp")) |
if (!strcmp(symbol->name,"_gp_disp")) |
184 |
return mipself_new_call16_reloc(abfd, reloc_entry, symbol, |
return mipself_new_call16_reloc(abfd, reloc_entry, symbol, |
192 |
into a non PIC sequence similar to HI16/LO16 sequences. */ |
into a non PIC sequence similar to HI16/LO16 sequences. */ |
193 |
addr = (bfd_byte*)(data) + reloc_entry->address; |
addr = (bfd_byte*)(data) + reloc_entry->address; |
194 |
insn = bfd_get_32(abfd, addr); |
insn = bfd_get_32(abfd, addr); |
195 |
|
|
196 |
/* Transform 'LW Rn, off(GP)' into 'LUI Rn, off' */ |
/* Transform 'LW Rn, off(GP)' into 'LUI Rn, off' */ |
197 |
if ((insn & 0xffe00000) != 0x8f800000) |
if ((insn & 0xffe00000) != 0x8f800000) |
198 |
return bfd_reloc_notsupported; |
return bfd_reloc_notsupported; |
199 |
|
|
200 |
insn &= ~0xffe00000; |
insn &= ~0xffe00000; |
201 |
insn |= 0x3c000000; |
insn |= 0x3c000000; |
202 |
|
|
203 |
bfd_put_32(abfd, insn, addr); |
bfd_put_32(abfd, insn, addr); |
204 |
|
|
205 |
/* We can then process it as HI16 */ |
/* We can then process it as HI16 */ |
206 |
return (*mipself_old_hi16_reloc)(abfd, reloc_entry, symbol, |
return (*mipself_old_hi16_reloc)(abfd, reloc_entry, symbol, |
207 |
data, input_section, |
data, input_section, |
208 |
output_bfd, error_message); |
output_bfd, error_message); |
209 |
|
|
210 |
} |
} |
211 |
|
|
212 |
|
|
213 |
/* mipself_install_patches -- install patches into BFD */ |
/* mipself_install_patches -- install patches into BFD */ |
214 |
|
|
215 |
static void |
static void |
216 |
mipself_install_patches(bfd *abfd) |
mipself_install_patches(bfd *abfd) { |
217 |
{ |
|
218 |
reloc_howto_type *howto; |
reloc_howto_type *howto; |
219 |
|
|
220 |
howto = bfd_reloc_type_lookup(abfd,BFD_RELOC_HI16_S); |
howto = bfd_reloc_type_lookup(abfd,BFD_RELOC_HI16_S); |
221 |
assert(howto); |
assert(howto); |
222 |
if (howto->special_function != mipself_new_hi16_reloc) |
if (howto->special_function != mipself_new_hi16_reloc) { |
223 |
{ |
|
224 |
mipself_old_hi16_reloc = howto->special_function; |
mipself_old_hi16_reloc = howto->special_function; |
225 |
*(void**)&(howto->special_function) = mipself_new_hi16_reloc; |
howto->special_function = mipself_new_hi16_reloc; |
226 |
assert(mipself_old_hi16_reloc); |
assert(mipself_old_hi16_reloc); |
227 |
} |
|
228 |
|
} |
229 |
|
|
230 |
/* LO16 */ |
/* LO16 */ |
231 |
howto = bfd_reloc_type_lookup(abfd,BFD_RELOC_LO16); |
howto = bfd_reloc_type_lookup(abfd,BFD_RELOC_LO16); |
232 |
assert(howto); |
assert(howto); |
233 |
if (howto->special_function != mipself_new_lo16_reloc) |
if (howto->special_function != mipself_new_lo16_reloc) { |
234 |
{ |
|
235 |
mipself_old_lo16_reloc = howto->special_function; |
mipself_old_lo16_reloc = howto->special_function; |
236 |
*(void**)&(howto->special_function) = mipself_new_lo16_reloc; |
howto->special_function = mipself_new_lo16_reloc; |
237 |
assert(mipself_old_lo16_reloc); |
assert(mipself_old_lo16_reloc); |
238 |
} |
|
239 |
|
} |
240 |
|
|
241 |
/* GOT16 */ |
/* GOT16 */ |
242 |
howto = bfd_reloc_type_lookup(abfd,BFD_RELOC_MIPS_GOT16); |
howto = bfd_reloc_type_lookup(abfd,BFD_RELOC_MIPS_GOT16); |
243 |
assert(howto); |
assert(howto); |
244 |
*(void**)&(howto->special_function) = mipself_new_got16_reloc; |
howto->special_function = mipself_new_got16_reloc; |
245 |
|
|
246 |
/* CALL16 */ |
/* CALL16 */ |
247 |
howto = bfd_reloc_type_lookup(abfd,BFD_RELOC_MIPS_CALL16); |
howto = bfd_reloc_type_lookup(abfd,BFD_RELOC_MIPS_CALL16); |
248 |
assert(howto); |
assert(howto); |
249 |
*(void**)&(howto->special_function) = mipself_new_call16_reloc; |
howto->special_function = mipself_new_call16_reloc; |
250 |
|
|
251 |
} |
} |
252 |
|
|
253 |
|
|
254 |
/* mipself_got_info -- structure containing GOT information */ |
/* mipself_got_info -- structure containing GOT information */ |
|
|
|
255 |
typedef struct mipself_got_info { |
typedef struct mipself_got_info { |
256 |
int gotsize; |
int gotsize; |
257 |
asection *sgot; |
asection *sgot; |
263 |
|
|
264 |
|
|
265 |
/* mipself_got_entry -- structure for GOT entries */ |
/* mipself_got_entry -- structure for GOT entries */ |
|
|
|
266 |
typedef struct mipself_got_entry { |
typedef struct mipself_got_entry { |
267 |
struct bfd_hash_entry root; |
struct bfd_hash_entry root; |
268 |
arelent *reloc; |
arelent *reloc; |
272 |
|
|
273 |
|
|
274 |
/* mipself_init_got_entry -- initialize got hash table component */ |
/* mipself_init_got_entry -- initialize got hash table component */ |
|
|
|
275 |
static struct bfd_hash_entry * |
static struct bfd_hash_entry * |
276 |
mipself_init_got_entry(struct bfd_hash_entry *entry, |
mipself_init_got_entry(struct bfd_hash_entry *entry, |
277 |
struct bfd_hash_table *table, |
struct bfd_hash_table *table, |
278 |
const char *string) |
const char *string) { |
279 |
{ |
|
280 |
mipself_got_entry *ret = (mipself_got_entry*)entry; |
mipself_got_entry *ret = (mipself_got_entry*)entry; |
281 |
if (!ret) |
|
282 |
{ |
if (!ret) { |
283 |
ret = (mipself_got_entry*) |
|
284 |
bfd_hash_allocate(table, sizeof(mipself_got_entry)); |
ret = (mipself_got_entry*) |
285 |
if (!ret) |
bfd_hash_allocate(table, sizeof(mipself_got_entry)); |
286 |
FEerror("bfd error:~S",1,bfd_errmsg(bfd_error_no_memory)); |
if (!ret) |
287 |
} |
FEerror("bfd error:~S",1,bfd_errmsg(bfd_error_no_memory)); |
288 |
|
|
289 |
|
} |
290 |
|
|
291 |
memset(ret, 0, sizeof(mipself_got_entry)); |
memset(ret, 0, sizeof(mipself_got_entry)); |
292 |
|
|
293 |
return bfd_hash_newfunc((struct bfd_hash_entry*)ret, table, string); |
return bfd_hash_newfunc((struct bfd_hash_entry*)ret, table, string); |
294 |
|
|
295 |
} |
} |
296 |
|
|
297 |
|
|
298 |
/* mipself_init_got_info -- initialize info about got */ |
/* mipself_init_got_info -- initialize info about got */ |
|
|
|
299 |
static void |
static void |
300 |
mipself_init_got_info(bfd *b, |
mipself_init_got_info(bfd *b, |
301 |
mipself_got_info *info) |
mipself_got_info *info) { |
302 |
{ |
|
303 |
/* Create GOT hash table */ |
/* Create GOT hash table */ |
304 |
info->sgot = NULL; |
info->sgot = NULL; |
305 |
info->gotsize = 0; |
info->gotsize = 0; |
306 |
|
|
307 |
bfd_hash_table_init(&info->got_table, mipself_init_got_entry); |
bfd_hash_table_init(&info->got_table, mipself_init_got_entry); |
308 |
|
|
309 |
/* Identify pertinent howto information */ |
/* Identify pertinent howto information */ |
310 |
info->reloc_got16 = bfd_reloc_type_lookup(b,BFD_RELOC_MIPS_GOT16); |
info->reloc_got16 = bfd_reloc_type_lookup(b,BFD_RELOC_MIPS_GOT16); |
311 |
info->reloc_call16 = bfd_reloc_type_lookup(b,BFD_RELOC_MIPS_CALL16); |
info->reloc_call16 = bfd_reloc_type_lookup(b,BFD_RELOC_MIPS_CALL16); |
312 |
info->reloc_32 = bfd_reloc_type_lookup(b,BFD_RELOC_32); |
info->reloc_32 = bfd_reloc_type_lookup(b,BFD_RELOC_32); |
313 |
|
|
314 |
} |
} |
315 |
|
|
316 |
|
|
317 |
/* mipself_free_got_info -- free got information */ |
/* mipself_free_got_info -- free got information */ |
|
|
|
318 |
static void |
static void |
319 |
mipself_free_got_info(mipself_got_info *info) |
mipself_free_got_info(mipself_got_info *info) { |
320 |
{ |
|
321 |
bfd_hash_table_free(&info->got_table); |
bfd_hash_table_free(&info->got_table); |
322 |
|
|
323 |
} |
} |
324 |
|
|
325 |
|
|
326 |
/* mipself_got_traverse -- got table traversal function */ |
/* mipself_got_traverse -- got table traversal function */ |
|
|
|
327 |
static int |
static int |
328 |
mipself_got_traverse(struct bfd_hash_entry *ent, void *gcookie) |
mipself_got_traverse(struct bfd_hash_entry *ent, void *gcookie) { |
329 |
{ |
|
330 |
mipself_got_entry *gotent = (mipself_got_entry*)ent; |
mipself_got_entry *gotent = (mipself_got_entry*)ent; |
331 |
asection *sgot = (asection*)gcookie; |
asection *sgot = (asection*)gcookie; |
332 |
/* sgot->orelocation[gotent->index] = gotent->reloc; */ |
|
333 |
sgot->relocation[gotent->index] = *gotent->reloc; |
sgot->relocation[gotent->index] = *gotent->reloc; |
334 |
|
|
335 |
return TRUE; |
return TRUE; |
336 |
|
|
337 |
} |
} |
338 |
|
|
339 |
|
|
340 |
/* mipself_create_got -- create a section for GOT */ |
/* mipself_create_got -- create a section for GOT */ |
|
|
|
341 |
static asection * |
static asection * |
342 |
mipself_create_got(bfd *b,asymbol **syms, |
mipself_create_got(bfd *b,asymbol **syms, |
343 |
mipself_got_info *info) |
mipself_got_info *info) { |
344 |
{ |
|
345 |
asection *sgot; |
asection *sgot; |
346 |
bfd_vma offset; |
bfd_vma offset; |
347 |
asection *p; |
asection *p; |
|
bfd *abfd; |
|
348 |
int i; |
int i; |
349 |
|
|
350 |
/* Check that there are no GOT section */ |
/* Check that there are no GOT section */ |
351 |
sgot = bfd_get_section_by_name(b, ".got"); |
sgot = bfd_get_section_by_name(b, ".got"); |
352 |
assert(!sgot); |
assert(!sgot); |
353 |
|
|
354 |
/* Compute GOT hash table */ |
/* Compute GOT hash table */ |
355 |
offset = 0; |
offset = 0; |
356 |
abfd = b; |
for (p=b->sections; p; p=p->next) |
357 |
for (p=abfd->sections; p; p=p->next) |
|
358 |
if ((p->flags & SEC_ALLOC) && (p->flags & SEC_RELOC)) |
if ((p->flags & SEC_ALLOC) && (p->flags & SEC_RELOC)) { |
359 |
{ |
|
360 |
int storage_needed,reloc_count; |
int storage_needed,reloc_count; |
361 |
arelent **reloc; |
arelent **reloc; |
362 |
|
|
363 |
/* MIPS native relocs: This section and analogs below have |
/* MIPS native relocs: This section and analogs below have |
364 |
been modified to avoid orelocation in favor of relocation |
been modified to avoid orelocation in favor of relocation |
365 |
itself. bfd_canonicalize_reloc reads in the relocation |
itself. bfd_canonicalize_reloc reads in the relocation |
366 |
table to the latter as an array and makes a pointer list |
table to the latter as an array and makes a pointer list |
367 |
to it in the supplied argument. We will call |
to it in the supplied argument. We will call |
368 |
bfd_get_relocated_section_contents, which will call |
bfd_get_relocated_section_contents, which will call |
369 |
bfd_canonicalize_reloc internally, on all sections, |
bfd_canonicalize_reloc internally, on all sections, |
370 |
including the new .got section. If no relocation array |
including the new .got section. If no relocation array |
371 |
exists, this will fail when bfd_cannicalize_reloc attempts |
exists, this will fail when bfd_cannicalize_reloc attempts |
372 |
to read in the non-existent table. 20050409 CM*/ |
to read in the non-existent table. 20050409 CM*/ |
373 |
|
|
374 |
|
|
375 |
storage_needed = bfd_get_reloc_upper_bound(b, p); |
storage_needed = bfd_get_reloc_upper_bound(b, p); |
376 |
assert(storage_needed>0); |
assert(storage_needed>0); |
377 |
/* reloc = xballoc(b,storage_needed); */ |
reloc=alloca(storage_needed); |
378 |
reloc=alloca(storage_needed); |
|
379 |
reloc_count = bfd_canonicalize_reloc(b, p, reloc, syms); |
reloc_count = bfd_canonicalize_reloc(b, p, reloc, syms); |
380 |
assert(reloc_count>0); |
assert(reloc_count>0); |
381 |
assert(p->reloc_count==0 || p->reloc_count==reloc_count); |
assert(p->reloc_count==0 || p->reloc_count==reloc_count); |
382 |
/* Keep relocation table in field orelocation (unused in input bfd) */ |
|
383 |
/* p->reloc_count = reloc_count; */ |
assert(p->relocation); |
384 |
/* p->orelocation = reloc; */ |
|
385 |
/* Mark symbols used by relocations with flag BSF_KEEP */ |
for (i=0; i<p->reloc_count; i++) { |
386 |
|
|
387 |
/* assert(p->orelocation); */ |
arelent *reloc = p->relocation+i; |
388 |
assert(p->relocation); |
asymbol *symbol = *(reloc->sym_ptr_ptr); |
389 |
for (i=0; i<p->reloc_count; i++) |
if ((reloc->howto==info->reloc_call16) |
390 |
{ |
|| ((reloc->howto==info->reloc_got16) |
391 |
/* arelent *reloc = p->orelocation[i]; */ |
&& !(symbol->flags & BSF_SECTION_SYM))) { |
392 |
arelent *reloc = p->relocation+i; |
|
393 |
asymbol *symbol = *(reloc->sym_ptr_ptr); |
/* Search entry in GOT table */ |
394 |
if ((reloc->howto==info->reloc_call16) |
const char *name = (*reloc->sym_ptr_ptr)->name; |
395 |
|| ((reloc->howto==info->reloc_got16) |
mipself_got_entry *gotent = |
396 |
&& !(symbol->flags & BSF_SECTION_SYM) ) ) |
(mipself_got_entry*) bfd_hash_lookup(&info->got_table, name, TRUE, TRUE ); |
397 |
{ |
|
398 |
/* Search entry in GOT table */ |
if (!gotent->reloc) { |
399 |
const char *name = (*reloc->sym_ptr_ptr)->name; |
|
400 |
mipself_got_entry *gotent = (mipself_got_entry*) |
/* Compute offset */ |
401 |
bfd_hash_lookup(&info->got_table, name, TRUE, TRUE ); |
gotent->index = info->gotsize; |
402 |
/* Fill entry */ |
gotent->offset = offset; |
403 |
if (!gotent->reloc) |
|
404 |
{ |
gotent->reloc = xballoc(b, sizeof(arelent)); |
405 |
/* Compute offset */ |
gotent->reloc->sym_ptr_ptr = reloc->sym_ptr_ptr; |
406 |
gotent->index = info->gotsize; |
gotent->reloc->address = offset; |
407 |
gotent->offset = offset; |
gotent->reloc->addend = 0; |
408 |
/* Prepare relocation entry */ |
gotent->reloc->howto = info->reloc_32; |
409 |
gotent->reloc = xballoc(b, sizeof(arelent)); |
|
410 |
gotent->reloc->sym_ptr_ptr = reloc->sym_ptr_ptr; |
/* Increment GOT offset */ |
411 |
gotent->reloc->address = offset; |
offset += sizeof(void*); |
412 |
gotent->reloc->addend = 0; |
info->gotsize += 1; |
413 |
gotent->reloc->howto = info->reloc_32; |
|
414 |
/* Increment GOT offset */ |
} |
415 |
offset += sizeof(void*); |
|
416 |
info->gotsize += 1; |
} |
417 |
} |
|
|
} |
|
|
} |
|
418 |
} |
} |
419 |
|
|
420 |
|
} |
421 |
|
|
422 |
/* Check GOT size */ |
/* Check GOT size */ |
423 |
if (offset >= 0x8000) |
if (offset >= 0x8000) |
424 |
FEerror("Too many entries in GOT (GOT full, merci MIPS)",0); |
FEerror("Too many entries in GOT (GOT full, merci MIPS)",0); |
425 |
|
|
426 |
/* Create GOT if necessary */ |
/* Create GOT if necessary */ |
427 |
if (info->gotsize > 0) |
if (info->gotsize > 0) { |
428 |
{ |
|
429 |
sgot = bfd_make_section(b, ".got"); |
sgot = bfd_make_section(b, ".got"); |
430 |
assert(sgot); |
assert(sgot); |
431 |
sgot->flags = SEC_ALLOC|SEC_RELOC|SEC_LOAD; |
sgot->flags = SEC_ALLOC|SEC_RELOC|SEC_LOAD; |
432 |
/* sgot->_raw_size = 0; */ |
|
433 |
/* sgot->_cooked_size = offset; */ |
/* MIPS native relocs: we need _raw_size set here too -- this is |
434 |
|
the generic way to do it, avoiding structure element name changes, |
435 |
/* MIPS native relocs: we need _raw_size set here too -- this is |
etc.*/ |
436 |
the generic way to do it, avoiding structure element name changes, |
|
437 |
etc.*/ |
if (!bfd_set_section_size(b,sgot,offset)) |
438 |
|
FEerror("Cannot set got section size",0); |
439 |
if (!bfd_set_section_size(b,sgot,offset)) |
|
440 |
FEerror("Cannot set got section size",0); |
if (sgot->alignment_power < 4) |
441 |
if (sgot->alignment_power < 4) |
sgot->alignment_power = 4; /* Set GOT relocations */ |
442 |
sgot->alignment_power = 4; /* Set GOT relocations */ |
|
443 |
/* sgot->orelocation = xballoc(b, info->gotsize*sizeof(void*)); */ |
sgot->relocation = xballoc(b, info->gotsize*sizeof(*sgot->relocation)); |
444 |
sgot->relocation = xballoc(b, info->gotsize*sizeof(*sgot->relocation)); |
bfd_hash_traverse(&info->got_table, (void*)mipself_got_traverse, sgot); |
445 |
bfd_hash_traverse(&info->got_table, (void*)mipself_got_traverse, sgot); |
sgot->reloc_count = info->gotsize; |
446 |
sgot->reloc_count = info->gotsize; |
|
447 |
} |
} |
448 |
|
|
449 |
/* return GOT section if any */ |
/* return GOT section if any */ |
450 |
info->sgot = sgot; |
info->sgot = sgot; |
451 |
return sgot; |
return sgot; |
452 |
|
|
453 |
} |
} |
454 |
|
|
455 |
|
|
456 |
/* mipself_fix_relocs -- patches the relocation for GOT */ |
/* mipself_fix_relocs -- patches the relocation for GOT */ |
|
|
|
457 |
static void |
static void |
458 |
mipself_fix_relocs(bfd *b,asymbol ** symbols,int symbol_count, |
mipself_fix_relocs(bfd *b,asymbol ** symbols,int symbol_count, |
459 |
mipself_got_info *info) |
mipself_got_info *info) { |
460 |
{ |
|
461 |
int i; |
int i; |
462 |
asymbol *gpdisp = NULL; |
asymbol *gpdisp = NULL; |
463 |
asymbol **gpdisp_ptr = NULL; |
asymbol **gpdisp_ptr = NULL; |
465 |
|
|
466 |
/* Locate and patch gpdisp symbol */ |
/* Locate and patch gpdisp symbol */ |
467 |
for (i=0; i<symbol_count; i++) |
for (i=0; i<symbol_count; i++) |
468 |
if (!strcmp(symbols[i]->name, "_gp_disp")) |
|
469 |
{ |
if (!strcmp(symbols[i]->name, "_gp_disp")) { |
470 |
gpdisp = symbols[i]; |
|
471 |
/* if (bfd_is_und_section(gpdisp->section)) */ |
gpdisp = symbols[i]; |
472 |
/* ent->undefined_symbol_count -= 1; */ |
gpdisp->value = 0; |
473 |
gpdisp->value = 0; |
gpdisp->flags = BSF_LOCAL|BSF_SECTION_SYM; |
474 |
gpdisp->flags = BSF_LOCAL|BSF_SECTION_SYM; |
gpdisp->section = info->sgot ? info->sgot : info->sgot : bfd_abs_section_ptr; |
475 |
if (info->sgot) |
gpdisp->udata.p = NULL; |
476 |
gpdisp->section = info->sgot; |
break; |
477 |
else |
} |
478 |
gpdisp->section = bfd_abs_section_ptr; |
|
|
gpdisp->udata.p = NULL; |
|
|
break; |
|
|
} |
|
479 |
if (!info->sgot) |
if (!info->sgot) |
480 |
return; |
return; |
481 |
|
|
482 |
if (!gpdisp) |
if (!gpdisp) |
483 |
FEerror("Found GOT relocations but no symbol '_gp_disp'",0); |
FEerror("Found GOT relocations but no symbol '_gp_disp'",0); |
484 |
|
|
487 |
*gpdisp_ptr = gpdisp; |
*gpdisp_ptr = gpdisp; |
488 |
|
|
489 |
/* Iterate on sections and relocations */ |
/* Iterate on sections and relocations */ |
490 |
for (p=b->sections; p; p=p->next) |
for (p=b->sections; p; p=p->next) |
491 |
{ |
|
492 |
if ((p->flags & SEC_ALLOC) && (p->flags & SEC_RELOC)) |
if ((p->flags & SEC_ALLOC) && (p->flags & SEC_RELOC)) { |
493 |
{ |
|
494 |
/* assert(p->orelocation); */ |
assert(p->relocation); |
495 |
assert(p->relocation); |
|
496 |
for (i=0; i<p->reloc_count; i++) |
for (i=0; i<p->reloc_count; i++) { |
497 |
{ |
|
498 |
/* arelent *reloc = p->orelocation[i]; */ |
arelent *reloc = p->relocation+i; |
499 |
arelent *reloc = p->relocation+i; |
asymbol *symbol = *reloc->sym_ptr_ptr; |
500 |
asymbol *symbol = *reloc->sym_ptr_ptr; |
|
501 |
if ((reloc->howto==info->reloc_call16) |
if ((reloc->howto==info->reloc_call16) |
502 |
|| ((reloc->howto==info->reloc_got16) |
|| ((reloc->howto==info->reloc_got16) |
503 |
&& !(symbol->flags & BSF_SECTION_SYM) ) ) |
&& !(symbol->flags & BSF_SECTION_SYM))) { |
504 |
{ |
|
505 |
/* Find GOT entry */ |
/* Find GOT entry */ |
506 |
mipself_got_entry *gotent = (mipself_got_entry*) |
mipself_got_entry *gotent = (mipself_got_entry*) |
507 |
bfd_hash_lookup(&info->got_table, symbol->name, FALSE, FALSE ); |
bfd_hash_lookup(&info->got_table, symbol->name, FALSE, FALSE ); |
508 |
assert(gotent); |
assert(gotent); |
509 |
/* Addend should be null */ |
|
510 |
if (reloc->addend) |
/* Addend should be null */ |
511 |
FEerror("Non zero addend in GOT16/CALL16 relocation",0); |
if (reloc->addend) |
512 |
/* GOT16 and CALL16 relocations will refer |
FEerror("Non zero addend in GOT16/CALL16 relocation",0); |
513 |
* to the GPDISP symbol and have the GOT index |
|
514 |
* in the addend */ |
/* GOT16 and CALL16 relocations will refer |
515 |
reloc->addend = gotent->offset; |
* to the GPDISP symbol and have the GOT index |
516 |
reloc->sym_ptr_ptr = gpdisp_ptr; |
* in the addend */ |
517 |
} |
reloc->addend = gotent->offset; |
518 |
} |
reloc->sym_ptr_ptr = gpdisp_ptr; |
519 |
} |
|
520 |
|
} |
521 |
|
|
522 |
|
} |
523 |
|
|
524 |
} |
} |
525 |
|
|
526 |
} |
} |
527 |
|
|
528 |
/* mipself_special -- special processing for mips elf */ |
/* mipself_special -- special processing for mips elf */ |
529 |
|
#define SPECIAL_BFD mipself_special |
530 |
static void |
static void |
531 |
mipself_special(bfd *b,asymbol **syms,int nsyms) |
SPECIAL_BFD(bfd *b,asymbol **syms,int nsyms) { |
532 |
{ |
|
533 |
/* MIPSELF case */ |
mipself_got_info got_info; |
534 |
if (bfd_get_flavour(b) == bfd_target_elf_flavour && |
mipself_install_patches(b); |
535 |
bfd_get_arch(b) == bfd_arch_mips ) |
mipself_init_got_info(b, &got_info); |
536 |
{ |
mipself_create_got(b, syms, &got_info); |
537 |
mipself_got_info got_info; |
mipself_fix_relocs(b,syms,nsyms, &got_info); |
538 |
/* Install BFD patches */ |
mipself_free_got_info(&got_info); |
539 |
mipself_install_patches(b); |
|
|
/* Create GOT section */ |
|
|
mipself_init_got_info(b, &got_info); |
|
|
mipself_create_got(b, syms, &got_info); |
|
|
mipself_fix_relocs(b,syms,nsyms, &got_info); |
|
|
mipself_free_got_info(&got_info); |
|
|
} |
|
540 |
} |
} |