1 |
/* BFD back-end for linux flavored sparc a.out binaries. |
/* BFD back-end for linux flavored sparc a.out binaries. |
2 |
Copyright 1992, 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2002 |
Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, |
3 |
Free Software Foundation, Inc. |
2003, 2004 Free Software Foundation, Inc. |
4 |
|
|
5 |
This file is part of BFD, the Binary File Descriptor library. |
This file is part of BFD, the Binary File Descriptor library. |
6 |
|
|
19 |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
20 |
USA. */ |
USA. */ |
21 |
|
|
22 |
#define TARGET_PAGE_SIZE 4096 |
#define TARGET_PAGE_SIZE 4096 |
23 |
#define ZMAGIC_DISK_BLOCK_SIZE 1024 |
#define ZMAGIC_DISK_BLOCK_SIZE 1024 |
24 |
#define SEGMENT_SIZE TARGET_PAGE_SIZE |
#define SEGMENT_SIZE TARGET_PAGE_SIZE |
25 |
#define TEXT_START_ADDR 0x0 |
#define TEXT_START_ADDR 0x0 |
26 |
#define N_SHARED_LIB(x) 0 |
#define N_SHARED_LIB(x) 0 |
|
#define BYTES_IN_WORD 4 |
|
27 |
|
|
28 |
#define MACHTYPE_OK(mtype) ((mtype) == M_SPARC || (mtype) == M_UNKNOWN) |
#define MACHTYPE_OK(mtype) ((mtype) == M_SPARC || (mtype) == M_UNKNOWN) |
29 |
|
|
51 |
static void MY_final_link_callback |
static void MY_final_link_callback |
52 |
PARAMS ((bfd *, file_ptr *, file_ptr *, file_ptr *)); |
PARAMS ((bfd *, file_ptr *, file_ptr *, file_ptr *)); |
53 |
|
|
54 |
static boolean sparclinux_bfd_final_link |
static bfd_boolean sparclinux_bfd_final_link |
55 |
PARAMS ((bfd *abfd, struct bfd_link_info *info)); |
PARAMS ((bfd *abfd, struct bfd_link_info *info)); |
56 |
|
|
57 |
static boolean |
static bfd_boolean |
58 |
sparclinux_bfd_final_link (abfd, info) |
sparclinux_bfd_final_link (abfd, info) |
59 |
bfd *abfd; |
bfd *abfd; |
60 |
struct bfd_link_info *info; |
struct bfd_link_info *info; |
67 |
|
|
68 |
/* Set the machine type correctly. */ |
/* Set the machine type correctly. */ |
69 |
|
|
70 |
static boolean sparclinux_write_object_contents PARAMS ((bfd *abfd)); |
static bfd_boolean sparclinux_write_object_contents PARAMS ((bfd *abfd)); |
71 |
|
|
72 |
static boolean |
static bfd_boolean |
73 |
sparclinux_write_object_contents (abfd) |
sparclinux_write_object_contents (abfd) |
74 |
bfd *abfd; |
bfd *abfd; |
75 |
{ |
{ |
82 |
|
|
83 |
WRITE_HEADERS(abfd, execp); |
WRITE_HEADERS(abfd, execp); |
84 |
|
|
85 |
return true; |
return TRUE; |
86 |
} |
} |
87 |
|
|
88 |
#define MY_write_object_contents sparclinux_write_object_contents |
#define MY_write_object_contents sparclinux_write_object_contents |
91 |
/* See if a symbol name is a reference to the global offset table. */ |
/* See if a symbol name is a reference to the global offset table. */ |
92 |
|
|
93 |
#ifndef GOT_REF_PREFIX |
#ifndef GOT_REF_PREFIX |
94 |
#define GOT_REF_PREFIX "__GOT_" |
#define GOT_REF_PREFIX "__GOT_" |
95 |
#endif |
#endif |
96 |
|
|
97 |
#define IS_GOT_SYM(name) \ |
#define IS_GOT_SYM(name) \ |
100 |
/* See if a symbol name is a reference to the procedure linkage table. */ |
/* See if a symbol name is a reference to the procedure linkage table. */ |
101 |
|
|
102 |
#ifndef PLT_REF_PREFIX |
#ifndef PLT_REF_PREFIX |
103 |
#define PLT_REF_PREFIX "__PLT_" |
#define PLT_REF_PREFIX "__PLT_" |
104 |
#endif |
#endif |
105 |
|
|
106 |
#define IS_PLT_SYM(name) \ |
#define IS_PLT_SYM(name) \ |
113 |
#endif |
#endif |
114 |
|
|
115 |
/* This special symbol is a set vector that contains a list of |
/* This special symbol is a set vector that contains a list of |
116 |
pointers to fixup tables. It will be present in any dynamicly |
pointers to fixup tables. It will be present in any dynamically |
117 |
linked file. The linker generated fixup table should also be added |
linked file. The linker generated fixup table should also be added |
118 |
to the list, and it should always appear in the second slot (the |
to the list, and it should always appear in the second slot (the |
119 |
first one is a dummy with a magic number that is defined in |
first one is a dummy with a magic number that is defined in |
178 |
PARAMS ((bfd *)); |
PARAMS ((bfd *)); |
179 |
static struct fixup *new_fixup |
static struct fixup *new_fixup |
180 |
PARAMS ((struct bfd_link_info *, struct linux_link_hash_entry *, |
PARAMS ((struct bfd_link_info *, struct linux_link_hash_entry *, |
181 |
bfd_vma, int)); |
bfd_vma, int)); |
182 |
static boolean linux_link_create_dynamic_sections |
static bfd_boolean linux_link_create_dynamic_sections |
183 |
PARAMS ((bfd *, struct bfd_link_info *)); |
PARAMS ((bfd *, struct bfd_link_info *)); |
184 |
static boolean linux_add_one_symbol |
static bfd_boolean linux_add_one_symbol |
185 |
PARAMS ((struct bfd_link_info *, bfd *, const char *, flagword, asection *, |
PARAMS ((struct bfd_link_info *, bfd *, const char *, flagword, asection *, |
186 |
bfd_vma, const char *, boolean, boolean, |
bfd_vma, const char *, bfd_boolean, bfd_boolean, |
187 |
struct bfd_link_hash_entry **)); |
struct bfd_link_hash_entry **)); |
188 |
static boolean linux_tally_symbols |
static bfd_boolean linux_tally_symbols |
189 |
PARAMS ((struct linux_link_hash_entry *, PTR)); |
PARAMS ((struct linux_link_hash_entry *, PTR)); |
190 |
static boolean linux_finish_dynamic_link |
static bfd_boolean linux_finish_dynamic_link |
191 |
PARAMS ((bfd *, struct bfd_link_info *)); |
PARAMS ((bfd *, struct bfd_link_info *)); |
192 |
|
|
193 |
/* Routine to create an entry in an Linux link hash table. */ |
/* Routine to create an entry in an Linux link hash table. */ |
204 |
subclass. */ |
subclass. */ |
205 |
if (ret == (struct linux_link_hash_entry *) NULL) |
if (ret == (struct linux_link_hash_entry *) NULL) |
206 |
ret = ((struct linux_link_hash_entry *) |
ret = ((struct linux_link_hash_entry *) |
207 |
bfd_hash_allocate (table, sizeof (struct linux_link_hash_entry))); |
bfd_hash_allocate (table, sizeof (struct linux_link_hash_entry))); |
208 |
if (ret == NULL) |
if (ret == NULL) |
209 |
return (struct bfd_hash_entry *) ret; |
return (struct bfd_hash_entry *) ret; |
210 |
|
|
211 |
/* Call the allocation method of the superclass. */ |
/* Call the allocation method of the superclass. */ |
212 |
ret = ((struct linux_link_hash_entry *) |
ret = ((struct linux_link_hash_entry *) |
213 |
NAME(aout,link_hash_newfunc) ((struct bfd_hash_entry *) ret, |
NAME(aout,link_hash_newfunc) ((struct bfd_hash_entry *) ret, |
214 |
table, string)); |
table, string)); |
215 |
if (ret != NULL) |
if (ret != NULL) |
216 |
{ |
{ |
217 |
/* Set local fields; there aren't any. */ |
/* Set local fields; there aren't any. */ |
233 |
if (ret == (struct linux_link_hash_table *) NULL) |
if (ret == (struct linux_link_hash_table *) NULL) |
234 |
return (struct bfd_link_hash_table *) NULL; |
return (struct bfd_link_hash_table *) NULL; |
235 |
if (! NAME(aout,link_hash_table_init) (&ret->root, abfd, |
if (! NAME(aout,link_hash_table_init) (&ret->root, abfd, |
236 |
linux_link_hash_newfunc)) |
linux_link_hash_newfunc)) |
237 |
{ |
{ |
238 |
free (ret); |
free (ret); |
239 |
return (struct bfd_link_hash_table *) NULL; |
return (struct bfd_link_hash_table *) NULL; |
252 |
#define linux_link_hash_lookup(table, string, create, copy, follow) \ |
#define linux_link_hash_lookup(table, string, create, copy, follow) \ |
253 |
((struct linux_link_hash_entry *) \ |
((struct linux_link_hash_entry *) \ |
254 |
aout_link_hash_lookup (&(table)->root, (string), (create), (copy),\ |
aout_link_hash_lookup (&(table)->root, (string), (create), (copy),\ |
255 |
(follow))) |
(follow))) |
256 |
|
|
257 |
/* Traverse a Linux link hash table. */ |
/* Traverse a Linux link hash table. */ |
258 |
|
|
259 |
#define linux_link_hash_traverse(table, func, info) \ |
#define linux_link_hash_traverse(table, func, info) \ |
260 |
(aout_link_hash_traverse \ |
(aout_link_hash_traverse \ |
261 |
(&(table)->root, \ |
(&(table)->root, \ |
262 |
(boolean (*) PARAMS ((struct aout_link_hash_entry *, PTR))) (func), \ |
(bfd_boolean (*) PARAMS ((struct aout_link_hash_entry *, PTR))) (func), \ |
263 |
(info))) |
(info))) |
264 |
|
|
265 |
/* Get the Linux link hash table from the info structure. This is |
/* Get the Linux link hash table from the info structure. This is |
279 |
struct fixup *f; |
struct fixup *f; |
280 |
|
|
281 |
f = (struct fixup *) bfd_hash_allocate (&info->hash->table, |
f = (struct fixup *) bfd_hash_allocate (&info->hash->table, |
282 |
sizeof (struct fixup)); |
sizeof (struct fixup)); |
283 |
if (f == NULL) |
if (f == NULL) |
284 |
return f; |
return f; |
285 |
f->next = linux_hash_table (info)->fixup_list; |
f->next = linux_hash_table (info)->fixup_list; |
299 |
know the size of the section, but that's OK - we just need to |
know the size of the section, but that's OK - we just need to |
300 |
create it for now. */ |
create it for now. */ |
301 |
|
|
302 |
static boolean |
static bfd_boolean |
303 |
linux_link_create_dynamic_sections (abfd, info) |
linux_link_create_dynamic_sections (abfd, info) |
304 |
bfd *abfd; |
bfd *abfd; |
305 |
struct bfd_link_info *info ATTRIBUTE_UNUSED; |
struct bfd_link_info *info ATTRIBUTE_UNUSED; |
311 |
flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; |
flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; |
312 |
|
|
313 |
/* We choose to use the name ".linux-dynamic" for the fixup table. |
/* We choose to use the name ".linux-dynamic" for the fixup table. |
314 |
Why not? */ |
Why not? */ |
315 |
s = bfd_make_section (abfd, ".linux-dynamic"); |
s = bfd_make_section (abfd, ".linux-dynamic"); |
316 |
if (s == NULL |
if (s == NULL |
317 |
|| ! bfd_set_section_flags (abfd, s, flags) |
|| ! bfd_set_section_flags (abfd, s, flags) |
318 |
|| ! bfd_set_section_alignment (abfd, s, 2)) |
|| ! bfd_set_section_alignment (abfd, s, 2)) |
319 |
return false; |
return FALSE; |
320 |
s->_raw_size = 0; |
s->size = 0; |
321 |
s->contents = 0; |
s->contents = 0; |
322 |
|
|
323 |
return true; |
return TRUE; |
324 |
} |
} |
325 |
|
|
326 |
/* Function to add a single symbol to the linker hash table. This is |
/* Function to add a single symbol to the linker hash table. This is |
327 |
a wrapper around _bfd_generic_link_add_one_symbol which handles the |
a wrapper around _bfd_generic_link_add_one_symbol which handles the |
328 |
tweaking needed for dynamic linking support. */ |
tweaking needed for dynamic linking support. */ |
329 |
|
|
330 |
static boolean |
static bfd_boolean |
331 |
linux_add_one_symbol (info, abfd, name, flags, section, value, string, |
linux_add_one_symbol (info, abfd, name, flags, section, value, string, |
332 |
copy, collect, hashp) |
copy, collect, hashp) |
333 |
struct bfd_link_info *info; |
struct bfd_link_info *info; |
334 |
bfd *abfd; |
bfd *abfd; |
335 |
const char *name; |
const char *name; |
337 |
asection *section; |
asection *section; |
338 |
bfd_vma value; |
bfd_vma value; |
339 |
const char *string; |
const char *string; |
340 |
boolean copy; |
bfd_boolean copy; |
341 |
boolean collect; |
bfd_boolean collect; |
342 |
struct bfd_link_hash_entry **hashp; |
struct bfd_link_hash_entry **hashp; |
343 |
{ |
{ |
344 |
struct linux_link_hash_entry *h; |
struct linux_link_hash_entry *h; |
345 |
boolean insert; |
bfd_boolean insert; |
346 |
|
|
347 |
/* Look up and see if we already have this symbol in the hash table. |
/* Look up and see if we already have this symbol in the hash table. |
348 |
If we do, and the defining entry is from a shared library, we |
If we do, and the defining entry is from a shared library, we |
352 |
be able to link Linux a.out and ELF objects together, but serious |
be able to link Linux a.out and ELF objects together, but serious |
353 |
confusion is possible. */ |
confusion is possible. */ |
354 |
|
|
355 |
insert = false; |
insert = FALSE; |
356 |
|
|
357 |
if (! info->relocateable |
if (! info->relocatable |
358 |
&& linux_hash_table (info)->dynobj == NULL |
&& linux_hash_table (info)->dynobj == NULL |
359 |
&& strcmp (name, SHARABLE_CONFLICTS) == 0 |
&& strcmp (name, SHARABLE_CONFLICTS) == 0 |
360 |
&& (flags & BSF_CONSTRUCTOR) != 0 |
&& (flags & BSF_CONSTRUCTOR) != 0 |
361 |
&& abfd->xvec == info->hash->creator) |
&& abfd->xvec == info->hash->creator) |
362 |
{ |
{ |
363 |
if (! linux_link_create_dynamic_sections (abfd, info)) |
if (! linux_link_create_dynamic_sections (abfd, info)) |
364 |
return false; |
return FALSE; |
365 |
linux_hash_table (info)->dynobj = abfd; |
linux_hash_table (info)->dynobj = abfd; |
366 |
insert = true; |
insert = TRUE; |
367 |
} |
} |
368 |
|
|
369 |
if (bfd_is_abs_section (section) |
if (bfd_is_abs_section (section) |
370 |
&& abfd->xvec == info->hash->creator) |
&& abfd->xvec == info->hash->creator) |
371 |
{ |
{ |
372 |
h = linux_link_hash_lookup (linux_hash_table (info), name, false, |
h = linux_link_hash_lookup (linux_hash_table (info), name, FALSE, |
373 |
false, false); |
FALSE, FALSE); |
374 |
if (h != NULL |
if (h != NULL |
375 |
&& (h->root.root.type == bfd_link_hash_defined |
&& (h->root.root.type == bfd_link_hash_defined |
376 |
|| h->root.root.type == bfd_link_hash_defweak)) |
|| h->root.root.type == bfd_link_hash_defweak)) |
377 |
{ |
{ |
378 |
struct fixup *f; |
struct fixup *f; |
379 |
|
|
380 |
if (hashp != NULL) |
if (hashp != NULL) |
381 |
*hashp = (struct bfd_link_hash_entry *) h; |
*hashp = (struct bfd_link_hash_entry *) h; |
382 |
|
|
383 |
f = new_fixup (info, h, value, ! IS_PLT_SYM (name)); |
f = new_fixup (info, h, value, ! IS_PLT_SYM (name)); |
384 |
if (f == NULL) |
if (f == NULL) |
385 |
return false; |
return FALSE; |
386 |
f->jump = IS_PLT_SYM (name); |
f->jump = IS_PLT_SYM (name); |
387 |
|
|
388 |
return true; |
return TRUE; |
389 |
} |
} |
390 |
} |
} |
391 |
|
|
392 |
/* Do the usual procedure for adding a symbol. */ |
/* Do the usual procedure for adding a symbol. */ |
393 |
if (! _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, |
if (! _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, |
394 |
value, string, copy, collect, |
value, string, copy, collect, |
395 |
hashp)) |
hashp)) |
396 |
return false; |
return FALSE; |
397 |
|
|
398 |
/* Insert a pointer to our table in the set vector. The dynamic |
/* Insert a pointer to our table in the set vector. The dynamic |
399 |
linker requires this information */ |
linker requires this information. */ |
400 |
if (insert) |
if (insert) |
401 |
{ |
{ |
402 |
asection *s; |
asection *s; |
403 |
|
|
404 |
/* Here we do our special thing to add the pointer to the |
/* Here we do our special thing to add the pointer to the |
405 |
dynamic section in the SHARABLE_CONFLICTS set vector. */ |
dynamic section in the SHARABLE_CONFLICTS set vector. */ |
406 |
s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, |
s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, |
407 |
".linux-dynamic"); |
".linux-dynamic"); |
408 |
BFD_ASSERT (s != NULL); |
BFD_ASSERT (s != NULL); |
409 |
|
|
410 |
if (! (_bfd_generic_link_add_one_symbol |
if (! (_bfd_generic_link_add_one_symbol |
411 |
(info, linux_hash_table (info)->dynobj, SHARABLE_CONFLICTS, |
(info, linux_hash_table (info)->dynobj, SHARABLE_CONFLICTS, |
412 |
BSF_GLOBAL | BSF_CONSTRUCTOR, s, (bfd_vma) 0, NULL, |
BSF_GLOBAL | BSF_CONSTRUCTOR, s, (bfd_vma) 0, NULL, |
413 |
false, false, NULL))) |
FALSE, FALSE, NULL))) |
414 |
return false; |
return FALSE; |
415 |
} |
} |
416 |
|
|
417 |
return true; |
return TRUE; |
418 |
} |
} |
419 |
|
|
420 |
/* We will crawl the hash table and come here for every global symbol. |
/* We will crawl the hash table and come here for every global symbol. |
427 |
|
|
428 |
This function is called via linux_link_hash_traverse. */ |
This function is called via linux_link_hash_traverse. */ |
429 |
|
|
430 |
static boolean |
static bfd_boolean |
431 |
linux_tally_symbols (h, data) |
linux_tally_symbols (h, data) |
432 |
struct linux_link_hash_entry *h; |
struct linux_link_hash_entry *h; |
433 |
PTR data; |
PTR data; |
436 |
struct fixup *f, *f1; |
struct fixup *f, *f1; |
437 |
int is_plt; |
int is_plt; |
438 |
struct linux_link_hash_entry *h1, *h2; |
struct linux_link_hash_entry *h1, *h2; |
439 |
boolean exists; |
bfd_boolean exists; |
440 |
|
|
441 |
if (h->root.root.type == bfd_link_hash_warning) |
if (h->root.root.type == bfd_link_hash_warning) |
442 |
h = (struct linux_link_hash_entry *) h->root.root.u.i.link; |
h = (struct linux_link_hash_entry *) h->root.root.u.i.link; |
443 |
|
|
444 |
if (h->root.root.type == bfd_link_hash_undefined |
if (h->root.root.type == bfd_link_hash_undefined |
445 |
&& strncmp (h->root.root.root.string, NEEDS_SHRLIB, |
&& strncmp (h->root.root.root.string, NEEDS_SHRLIB, |
446 |
sizeof NEEDS_SHRLIB - 1) == 0) |
sizeof NEEDS_SHRLIB - 1) == 0) |
447 |
{ |
{ |
448 |
const char *name; |
const char *name; |
449 |
char *p; |
char *p; |
452 |
name = h->root.root.root.string + sizeof NEEDS_SHRLIB - 1; |
name = h->root.root.root.string + sizeof NEEDS_SHRLIB - 1; |
453 |
p = strrchr (name, '_'); |
p = strrchr (name, '_'); |
454 |
if (p != NULL) |
if (p != NULL) |
455 |
alloc = (char *) bfd_malloc ((bfd_size_type) strlen (name) + 1); |
alloc = (char *) bfd_malloc ((bfd_size_type) strlen (name) + 1); |
456 |
|
|
457 |
if (p == NULL || alloc == NULL) |
if (p == NULL || alloc == NULL) |
458 |
(*_bfd_error_handler) (_("Output file requires shared library `%s'\n"), |
(*_bfd_error_handler) (_("Output file requires shared library `%s'\n"), |
459 |
name); |
name); |
460 |
else |
else |
461 |
{ |
{ |
462 |
strcpy (alloc, name); |
strcpy (alloc, name); |
463 |
p = strrchr (alloc, '_'); |
p = strrchr (alloc, '_'); |
464 |
*p++ = '\0'; |
*p++ = '\0'; |
465 |
(*_bfd_error_handler) |
(*_bfd_error_handler) |
466 |
(_("Output file requires shared library `%s.so.%s'\n"), |
(_("Output file requires shared library `%s.so.%s'\n"), |
467 |
alloc, p); |
alloc, p); |
468 |
free (alloc); |
free (alloc); |
469 |
} |
} |
470 |
|
|
471 |
abort (); |
abort (); |
472 |
} |
} |
478 |
if (is_plt || IS_GOT_SYM (h->root.root.root.string)) |
if (is_plt || IS_GOT_SYM (h->root.root.root.string)) |
479 |
{ |
{ |
480 |
/* Look up this symbol twice. Once just as a regular lookup, |
/* Look up this symbol twice. Once just as a regular lookup, |
481 |
and then again following all of the indirect links until we |
and then again following all of the indirect links until we |
482 |
reach a real symbol. */ |
reach a real symbol. */ |
483 |
h1 = linux_link_hash_lookup (linux_hash_table (info), |
h1 = linux_link_hash_lookup (linux_hash_table (info), |
484 |
(h->root.root.root.string |
(h->root.root.root.string |
485 |
+ sizeof PLT_REF_PREFIX - 1), |
+ sizeof PLT_REF_PREFIX - 1), |
486 |
false, false, true); |
FALSE, FALSE, TRUE); |
487 |
/* h2 does not follow indirect symbols. */ |
/* h2 does not follow indirect symbols. */ |
488 |
h2 = linux_link_hash_lookup (linux_hash_table (info), |
h2 = linux_link_hash_lookup (linux_hash_table (info), |
489 |
(h->root.root.root.string |
(h->root.root.root.string |
490 |
+ sizeof PLT_REF_PREFIX - 1), |
+ sizeof PLT_REF_PREFIX - 1), |
491 |
false, false, false); |
FALSE, FALSE, FALSE); |
492 |
|
|
493 |
/* The real symbol must exist but if it is also an ABS symbol, |
/* The real symbol must exist but if it is also an ABS symbol, |
494 |
there is no need to have a fixup. This is because they both |
there is no need to have a fixup. This is because they both |
495 |
came from the same library. If on the other hand, we had to |
came from the same library. If on the other hand, we had to |
496 |
use an indirect symbol to get to the real symbol, we add the |
use an indirect symbol to get to the real symbol, we add the |
497 |
fixup anyway, since there are cases where these symbols come |
fixup anyway, since there are cases where these symbols come |
498 |
from different shared libraries */ |
from different shared libraries */ |
499 |
if (h1 != NULL |
if (h1 != NULL |
500 |
&& (((h1->root.root.type == bfd_link_hash_defined |
&& (((h1->root.root.type == bfd_link_hash_defined |
501 |
|| h1->root.root.type == bfd_link_hash_defweak) |
|| h1->root.root.type == bfd_link_hash_defweak) |
502 |
&& ! bfd_is_abs_section (h1->root.root.u.def.section)) |
&& ! bfd_is_abs_section (h1->root.root.u.def.section)) |
503 |
|| h2->root.root.type == bfd_link_hash_indirect)) |
|| h2->root.root.type == bfd_link_hash_indirect)) |
504 |
{ |
{ |
505 |
/* See if there is a "builtin" fixup already present |
/* See if there is a "builtin" fixup already present |
506 |
involving this symbol. If so, convert it to a regular |
involving this symbol. If so, convert it to a regular |
507 |
fixup. In the end, this relaxes some of the requirements |
fixup. In the end, this relaxes some of the requirements |
508 |
about the order of performing fixups. */ |
about the order of performing fixups. */ |
509 |
exists = false; |
exists = FALSE; |
510 |
for (f1 = linux_hash_table (info)->fixup_list; |
for (f1 = linux_hash_table (info)->fixup_list; |
511 |
f1 != NULL; |
f1 != NULL; |
512 |
f1 = f1->next) |
f1 = f1->next) |
513 |
{ |
{ |
514 |
if ((f1->h != h && f1->h != h1) |
if ((f1->h != h && f1->h != h1) |
515 |
|| (! f1->builtin && ! f1->jump)) |
|| (! f1->builtin && ! f1->jump)) |
516 |
continue; |
continue; |
517 |
if (f1->h == h1) |
if (f1->h == h1) |
518 |
exists = true; |
exists = TRUE; |
519 |
if (! exists |
if (! exists |
520 |
&& bfd_is_abs_section (h->root.root.u.def.section)) |
&& bfd_is_abs_section (h->root.root.u.def.section)) |
521 |
{ |
{ |
522 |
f = new_fixup (info, h1, f1->h->root.root.u.def.value, 0); |
f = new_fixup (info, h1, f1->h->root.root.u.def.value, 0); |
523 |
f->jump = is_plt; |
f->jump = is_plt; |
524 |
} |
} |
525 |
f1->h = h1; |
f1->h = h1; |
526 |
f1->jump = is_plt; |
f1->jump = is_plt; |
527 |
f1->builtin = 0; |
f1->builtin = 0; |
528 |
exists = true; |
exists = TRUE; |
529 |
} |
} |
530 |
if (! exists |
if (! exists |
531 |
&& bfd_is_abs_section (h->root.root.u.def.section)) |
&& bfd_is_abs_section (h->root.root.u.def.section)) |
532 |
{ |
{ |
533 |
f = new_fixup (info, h1, h->root.root.u.def.value, 0); |
f = new_fixup (info, h1, h->root.root.u.def.value, 0); |
534 |
if (f == NULL) |
if (f == NULL) |
535 |
{ |
{ |
536 |
/* FIXME: No way to return error. */ |
/* FIXME: No way to return error. */ |
537 |
abort (); |
abort (); |
538 |
} |
} |
539 |
f->jump = is_plt; |
f->jump = is_plt; |
540 |
} |
} |
541 |
} |
} |
542 |
|
|
543 |
/* Quick and dirty way of stripping these symbols from the |
/* Quick and dirty way of stripping these symbols from the |
544 |
symtab. */ |
symtab. */ |
545 |
if (bfd_is_abs_section (h->root.root.u.def.section)) |
if (bfd_is_abs_section (h->root.root.u.def.section)) |
546 |
h->root.written = true; |
h->root.written = TRUE; |
547 |
} |
} |
548 |
|
|
549 |
return true; |
return TRUE; |
550 |
} |
} |
551 |
|
|
552 |
/* This is called to set the size of the .linux-dynamic section is. |
/* This is called to set the size of the .linux-dynamic section is. |
555 |
we just scan the hash tables to find out how many additional fixups |
we just scan the hash tables to find out how many additional fixups |
556 |
are required. */ |
are required. */ |
557 |
|
|
558 |
boolean |
bfd_boolean |
559 |
bfd_sparclinux_size_dynamic_sections (output_bfd, info) |
bfd_sparclinux_size_dynamic_sections (output_bfd, info) |
560 |
bfd *output_bfd; |
bfd *output_bfd; |
561 |
struct bfd_link_info *info; |
struct bfd_link_info *info; |
564 |
asection *s; |
asection *s; |
565 |
|
|
566 |
if (output_bfd->xvec != &MY(vec)) |
if (output_bfd->xvec != &MY(vec)) |
567 |
return true; |
return TRUE; |
568 |
|
|
569 |
/* First find the fixups... */ |
/* First find the fixups... */ |
570 |
linux_link_hash_traverse (linux_hash_table (info), |
linux_link_hash_traverse (linux_hash_table (info), |
571 |
linux_tally_symbols, |
linux_tally_symbols, |
572 |
(PTR) info); |
(PTR) info); |
573 |
|
|
574 |
/* If there are builtin fixups, leave room for a marker. This is |
/* If there are builtin fixups, leave room for a marker. This is |
575 |
used by the dynamic linker so that it knows that all that follow |
used by the dynamic linker so that it knows that all that follow |
577 |
for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next) |
for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next) |
578 |
{ |
{ |
579 |
if (f->builtin) |
if (f->builtin) |
580 |
{ |
{ |
581 |
++linux_hash_table (info)->fixup_count; |
++linux_hash_table (info)->fixup_count; |
582 |
++linux_hash_table (info)->local_builtins; |
++linux_hash_table (info)->local_builtins; |
583 |
break; |
break; |
584 |
} |
} |
585 |
} |
} |
586 |
|
|
587 |
if (linux_hash_table (info)->dynobj == NULL) |
if (linux_hash_table (info)->dynobj == NULL) |
588 |
{ |
{ |
589 |
if (linux_hash_table (info)->fixup_count > 0) |
if (linux_hash_table (info)->fixup_count > 0) |
590 |
abort (); |
abort (); |
591 |
return true; |
return TRUE; |
592 |
} |
} |
593 |
|
|
594 |
/* Allocate memory for our fixup table. We will fill it in later. */ |
/* Allocate memory for our fixup table. We will fill it in later. */ |
595 |
s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, |
s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, |
596 |
".linux-dynamic"); |
".linux-dynamic"); |
597 |
if (s != NULL) |
if (s != NULL) |
598 |
{ |
{ |
599 |
s->_raw_size = linux_hash_table (info)->fixup_count + 1; |
s->size = linux_hash_table (info)->fixup_count + 1; |
600 |
s->_raw_size *= 8; |
s->size *= 8; |
601 |
s->contents = (bfd_byte *) bfd_zalloc (output_bfd, s->_raw_size); |
s->contents = (bfd_byte *) bfd_zalloc (output_bfd, s->size); |
602 |
if (s->contents == NULL) |
if (s->contents == NULL) |
603 |
return false; |
return FALSE; |
604 |
} |
} |
605 |
|
|
606 |
return true; |
return TRUE; |
607 |
} |
} |
608 |
|
|
609 |
/* We come here once we are ready to actually write the fixup table to |
/* We come here once we are ready to actually write the fixup table to |
610 |
the output file. Scan the fixup tables and so forth and generate |
the output file. Scan the fixup tables and so forth and generate |
611 |
the stuff we need. */ |
the stuff we need. */ |
612 |
|
|
613 |
static boolean |
static bfd_boolean |
614 |
linux_finish_dynamic_link (output_bfd, info) |
linux_finish_dynamic_link (output_bfd, info) |
615 |
bfd *output_bfd; |
bfd *output_bfd; |
616 |
struct bfd_link_info *info; |
struct bfd_link_info *info; |
624 |
unsigned int fixups_written; |
unsigned int fixups_written; |
625 |
|
|
626 |
if (linux_hash_table (info)->dynobj == NULL) |
if (linux_hash_table (info)->dynobj == NULL) |
627 |
return true; |
return TRUE; |
628 |
|
|
629 |
s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, |
s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, |
630 |
".linux-dynamic"); |
".linux-dynamic"); |
631 |
BFD_ASSERT (s != NULL); |
BFD_ASSERT (s != NULL); |
632 |
os = s->output_section; |
os = s->output_section; |
633 |
fixups_written = 0; |
fixups_written = 0; |
634 |
|
|
635 |
#ifdef LINUX_LINK_DEBUG |
#ifdef LINUX_LINK_DEBUG |
636 |
printf ("Fixup table file offset: %x VMA: %x\n", |
printf ("Fixup table file offset: %x VMA: %x\n", |
637 |
os->filepos + s->output_offset, |
os->filepos + s->output_offset, |
638 |
os->vma + s->output_offset); |
os->vma + s->output_offset); |
639 |
#endif |
#endif |
640 |
|
|
641 |
fixup_table = s->contents; |
fixup_table = s->contents; |
647 |
for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next) |
for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next) |
648 |
{ |
{ |
649 |
if (f->builtin) |
if (f->builtin) |
650 |
continue; |
continue; |
651 |
|
|
652 |
if (f->h->root.root.type != bfd_link_hash_defined |
if (f->h->root.root.type != bfd_link_hash_defined |
653 |
&& f->h->root.root.type != bfd_link_hash_defweak) |
&& f->h->root.root.type != bfd_link_hash_defweak) |
654 |
{ |
{ |
655 |
(*_bfd_error_handler) |
(*_bfd_error_handler) |
656 |
(_("Symbol %s not defined for fixups\n"), |
(_("Symbol %s not defined for fixups\n"), |
657 |
f->h->root.root.root.string); |
f->h->root.root.root.string); |
658 |
continue; |
continue; |
659 |
} |
} |
660 |
|
|
661 |
is = f->h->root.root.u.def.section; |
is = f->h->root.root.u.def.section; |
662 |
section_offset = is->output_section->vma + is->output_offset; |
section_offset = is->output_section->vma + is->output_offset; |
664 |
|
|
665 |
#ifdef LINUX_LINK_DEBUG |
#ifdef LINUX_LINK_DEBUG |
666 |
printf ("Fixup(%d) %s: %x %x\n",f->jump, f->h->root.root.string, |
printf ("Fixup(%d) %s: %x %x\n",f->jump, f->h->root.root.string, |
667 |
new_addr, f->value); |
new_addr, f->value); |
668 |
#endif |
#endif |
669 |
|
|
670 |
if (f->jump) |
if (f->jump) |
671 |
{ |
{ |
672 |
/* Relative address */ |
/* Relative address */ |
673 |
new_addr = new_addr - (f->value + 5); |
new_addr = new_addr - (f->value + 5); |
674 |
bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table); |
bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table); |
675 |
fixup_table += 4; |
fixup_table += 4; |
676 |
bfd_put_32 (output_bfd, f->value + 1, fixup_table); |
bfd_put_32 (output_bfd, f->value + 1, fixup_table); |
677 |
fixup_table += 4; |
fixup_table += 4; |
678 |
} |
} |
679 |
else |
else |
680 |
{ |
{ |
681 |
bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table); |
bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table); |
682 |
fixup_table += 4; |
fixup_table += 4; |
683 |
bfd_put_32 (output_bfd, f->value, fixup_table); |
bfd_put_32 (output_bfd, f->value, fixup_table); |
684 |
fixup_table += 4; |
fixup_table += 4; |
685 |
} |
} |
686 |
++fixups_written; |
++fixups_written; |
687 |
} |
} |
688 |
|
|
695 |
fixup_table += 4; |
fixup_table += 4; |
696 |
++fixups_written; |
++fixups_written; |
697 |
for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next) |
for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next) |
698 |
{ |
{ |
699 |
if (! f->builtin) |
if (! f->builtin) |
700 |
continue; |
continue; |
701 |
|
|
702 |
if (f->h->root.root.type != bfd_link_hash_defined |
if (f->h->root.root.type != bfd_link_hash_defined |
703 |
&& f->h->root.root.type != bfd_link_hash_defweak) |
&& f->h->root.root.type != bfd_link_hash_defweak) |
704 |
{ |
{ |
705 |
(*_bfd_error_handler) |
(*_bfd_error_handler) |
706 |
(_("Symbol %s not defined for fixups\n"), |
(_("Symbol %s not defined for fixups\n"), |
707 |
f->h->root.root.root.string); |
f->h->root.root.root.string); |
708 |
continue; |
continue; |
709 |
} |
} |
710 |
|
|
711 |
is = f->h->root.root.u.def.section; |
is = f->h->root.root.u.def.section; |
712 |
section_offset = is->output_section->vma + is->output_offset; |
section_offset = is->output_section->vma + is->output_offset; |
713 |
new_addr = f->h->root.root.u.def.value + section_offset; |
new_addr = f->h->root.root.u.def.value + section_offset; |
714 |
|
|
715 |
#ifdef LINUX_LINK_DEBUG |
#ifdef LINUX_LINK_DEBUG |
716 |
printf ("Fixup(B) %s: %x %x\n", f->h->root.root.string, |
printf ("Fixup(B) %s: %x %x\n", f->h->root.root.string, |
717 |
new_addr, f->value); |
new_addr, f->value); |
718 |
#endif |
#endif |
719 |
|
|
720 |
bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table); |
bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table); |
721 |
fixup_table += 4; |
fixup_table += 4; |
722 |
bfd_put_32 (output_bfd, f->value, fixup_table); |
bfd_put_32 (output_bfd, f->value, fixup_table); |
723 |
fixup_table += 4; |
fixup_table += 4; |
724 |
++fixups_written; |
++fixups_written; |
725 |
} |
} |
726 |
} |
} |
727 |
|
|
728 |
if (linux_hash_table (info)->fixup_count != fixups_written) |
if (linux_hash_table (info)->fixup_count != fixups_written) |
729 |
{ |
{ |
730 |
(*_bfd_error_handler) (_("Warning: fixup count mismatch\n")); |
(*_bfd_error_handler) (_("Warning: fixup count mismatch\n")); |
731 |
while (linux_hash_table (info)->fixup_count > fixups_written) |
while (linux_hash_table (info)->fixup_count > fixups_written) |
732 |
{ |
{ |
733 |
bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table); |
bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table); |
734 |
fixup_table += 4; |
fixup_table += 4; |
735 |
bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table); |
bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table); |
736 |
fixup_table += 4; |
fixup_table += 4; |
737 |
++fixups_written; |
++fixups_written; |
738 |
} |
} |
739 |
} |
} |
740 |
|
|
741 |
h = linux_link_hash_lookup (linux_hash_table (info), |
h = linux_link_hash_lookup (linux_hash_table (info), |
742 |
"__BUILTIN_FIXUPS__", |
"__BUILTIN_FIXUPS__", |
743 |
false, false, false); |
FALSE, FALSE, FALSE); |
744 |
|
|
745 |
if (h != NULL |
if (h != NULL |
746 |
&& (h->root.root.type == bfd_link_hash_defined |
&& (h->root.root.type == bfd_link_hash_defined |
747 |
|| h->root.root.type == bfd_link_hash_defweak)) |
|| h->root.root.type == bfd_link_hash_defweak)) |
748 |
{ |
{ |
749 |
is = h->root.root.u.def.section; |
is = h->root.root.u.def.section; |
750 |
section_offset = is->output_section->vma + is->output_offset; |
section_offset = is->output_section->vma + is->output_offset; |
761 |
|
|
762 |
if (bfd_seek (output_bfd, (file_ptr) (os->filepos + s->output_offset), |
if (bfd_seek (output_bfd, (file_ptr) (os->filepos + s->output_offset), |
763 |
SEEK_SET) != 0) |
SEEK_SET) != 0) |
764 |
return false; |
return FALSE; |
765 |
|
|
766 |
if (bfd_bwrite ((PTR) s->contents, s->_raw_size, output_bfd) |
if (bfd_bwrite ((PTR) s->contents, s->size, output_bfd) != s->size) |
767 |
!= s->_raw_size) |
return FALSE; |
|
return false; |
|
768 |
|
|
769 |
return true; |
return TRUE; |
770 |
} |
} |
771 |
|
|
772 |
#define MY_bfd_link_hash_table_create linux_link_hash_table_create |
#define MY_bfd_link_hash_table_create linux_link_hash_table_create |