160484Sobrien/* BFD back-end for linux flavored sparc a.out binaries. 2218822Sdim Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 3218822Sdim 2003, 2004, 2006, 2007 Free Software Foundation, Inc. 460484Sobrien 5218822Sdim This file is part of BFD, the Binary File Descriptor library. 660484Sobrien 7218822Sdim This program is free software; you can redistribute it and/or modify 8218822Sdim it under the terms of the GNU General Public License as published by 9218822Sdim the Free Software Foundation; either version 2 of the License, or 10218822Sdim (at your option) any later version. 1160484Sobrien 12218822Sdim This program is distributed in the hope that it will be useful, 13218822Sdim but WITHOUT ANY WARRANTY; without even the implied warranty of 14218822Sdim MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15218822Sdim GNU General Public License for more details. 1660484Sobrien 17218822Sdim You should have received a copy of the GNU General Public License 18218822Sdim along with this program; if not, write to the Free Software 19218822Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 20218822Sdim USA. */ 2160484Sobrien 22130561Sobrien#define TARGET_PAGE_SIZE 4096 23130561Sobrien#define ZMAGIC_DISK_BLOCK_SIZE 1024 24130561Sobrien#define SEGMENT_SIZE TARGET_PAGE_SIZE 25130561Sobrien#define TEXT_START_ADDR 0x0 26130561Sobrien#define N_SHARED_LIB(x) 0 2760484Sobrien 2860484Sobrien#define MACHTYPE_OK(mtype) ((mtype) == M_SPARC || (mtype) == M_UNKNOWN) 2960484Sobrien 30218822Sdim#include "sysdep.h" 3160484Sobrien#include "bfd.h" 3260484Sobrien#include "libbfd.h" 3360484Sobrien#include "aout/aout64.h" 3460484Sobrien#include "aout/stab_gnu.h" 3560484Sobrien#include "aout/ar.h" 3660484Sobrien#include "libaout.h" /* BFD a.out internal data structures */ 3760484Sobrien 3860484Sobrien#define DEFAULT_ARCH bfd_arch_sparc 3989857Sobrien/* Do not "beautify" the CONCAT* macro args. Traditional C will not 4089857Sobrien remove whitespace added here, and thus will fail to concatenate 4189857Sobrien the tokens. */ 4289857Sobrien#define MY(OP) CONCAT2 (sparclinux_,OP) 4360484Sobrien#define TARGETNAME "a.out-sparc-linux" 4460484Sobrien 4560484Sobrienextern const bfd_target MY(vec); 4660484Sobrien 4760484Sobrien/* We always generate QMAGIC files in preference to ZMAGIC files. It 4860484Sobrien would be possible to make this a linker option, if that ever 4960484Sobrien becomes important. */ 5060484Sobrien 5160484Sobrienstatic void MY_final_link_callback 5260484Sobrien PARAMS ((bfd *, file_ptr *, file_ptr *, file_ptr *)); 5360484Sobrien 54130561Sobrienstatic bfd_boolean sparclinux_bfd_final_link 5560484Sobrien PARAMS ((bfd *abfd, struct bfd_link_info *info)); 5660484Sobrien 57130561Sobrienstatic bfd_boolean 5860484Sobriensparclinux_bfd_final_link (abfd, info) 5960484Sobrien bfd *abfd; 6060484Sobrien struct bfd_link_info *info; 6160484Sobrien{ 6260484Sobrien obj_aout_subformat (abfd) = q_magic_format; 6360484Sobrien return NAME(aout,final_link) (abfd, info, MY_final_link_callback); 6460484Sobrien} 6560484Sobrien 6660484Sobrien#define MY_bfd_final_link sparclinux_bfd_final_link 6760484Sobrien 6860484Sobrien/* Set the machine type correctly. */ 6960484Sobrien 70130561Sobrienstatic bfd_boolean sparclinux_write_object_contents PARAMS ((bfd *abfd)); 7160484Sobrien 72130561Sobrienstatic bfd_boolean 7360484Sobriensparclinux_write_object_contents (abfd) 7460484Sobrien bfd *abfd; 7560484Sobrien{ 7660484Sobrien struct external_exec exec_bytes; 7760484Sobrien struct internal_exec *execp = exec_hdr (abfd); 7860484Sobrien 7960484Sobrien N_SET_MACHTYPE (*execp, M_SPARC); 8060484Sobrien 8160484Sobrien obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; 8260484Sobrien 8360484Sobrien WRITE_HEADERS(abfd, execp); 8460484Sobrien 85130561Sobrien return TRUE; 8660484Sobrien} 8760484Sobrien 8860484Sobrien#define MY_write_object_contents sparclinux_write_object_contents 8960484Sobrien/* Code to link against Linux a.out shared libraries. */ 9060484Sobrien 9160484Sobrien/* See if a symbol name is a reference to the global offset table. */ 9260484Sobrien 9360484Sobrien#ifndef GOT_REF_PREFIX 94130561Sobrien#define GOT_REF_PREFIX "__GOT_" 9560484Sobrien#endif 9660484Sobrien 97218822Sdim#define IS_GOT_SYM(name) (CONST_STRNEQ (name, GOT_REF_PREFIX)) 9860484Sobrien 9977298Sobrien/* See if a symbol name is a reference to the procedure linkage table. */ 10060484Sobrien 10160484Sobrien#ifndef PLT_REF_PREFIX 102130561Sobrien#define PLT_REF_PREFIX "__PLT_" 10360484Sobrien#endif 10460484Sobrien 105218822Sdim#define IS_PLT_SYM(name) (CONST_STRNEQ (name, PLT_REF_PREFIX)) 10660484Sobrien 10760484Sobrien/* This string is used to generate specialized error messages. */ 10860484Sobrien 10960484Sobrien#ifndef NEEDS_SHRLIB 11060484Sobrien#define NEEDS_SHRLIB "__NEEDS_SHRLIB_" 11160484Sobrien#endif 11260484Sobrien 11360484Sobrien/* This special symbol is a set vector that contains a list of 114130561Sobrien pointers to fixup tables. It will be present in any dynamically 11560484Sobrien linked file. The linker generated fixup table should also be added 11660484Sobrien to the list, and it should always appear in the second slot (the 11760484Sobrien first one is a dummy with a magic number that is defined in 11860484Sobrien crt0.o). */ 11960484Sobrien 12060484Sobrien#ifndef SHARABLE_CONFLICTS 12160484Sobrien#define SHARABLE_CONFLICTS "__SHARABLE_CONFLICTS__" 12260484Sobrien#endif 12360484Sobrien 12460484Sobrien/* We keep a list of fixups. The terminology is a bit strange, but 12560484Sobrien each fixup contains two 32 bit numbers. A regular fixup contains 12660484Sobrien an address and a pointer, and at runtime we should store the 12760484Sobrien address at the location pointed to by the pointer. A builtin fixup 12860484Sobrien contains two pointers, and we should read the address using one 12960484Sobrien pointer and store it at the location pointed to by the other 13060484Sobrien pointer. Builtin fixups come into play when we have duplicate 13160484Sobrien __GOT__ symbols for the same variable. The builtin fixup will copy 13260484Sobrien the GOT pointer from one over into the other. */ 13360484Sobrien 13460484Sobrienstruct fixup 13560484Sobrien{ 13660484Sobrien struct fixup *next; 13760484Sobrien struct linux_link_hash_entry *h; 13860484Sobrien bfd_vma value; 13960484Sobrien 14060484Sobrien /* Nonzero if this is a jump instruction that needs to be fixed, 14160484Sobrien zero if this is just a pointer */ 14260484Sobrien char jump; 14360484Sobrien 14460484Sobrien char builtin; 14560484Sobrien}; 14660484Sobrien 14760484Sobrien/* We don't need a special hash table entry structure, but we do need 14860484Sobrien to keep some information between linker passes, so we use a special 14960484Sobrien hash table. */ 15060484Sobrien 15160484Sobrienstruct linux_link_hash_entry 15260484Sobrien{ 15360484Sobrien struct aout_link_hash_entry root; 15460484Sobrien}; 15560484Sobrien 15660484Sobrienstruct linux_link_hash_table 15760484Sobrien{ 15860484Sobrien struct aout_link_hash_table root; 15960484Sobrien 16060484Sobrien /* First dynamic object found in link. */ 16160484Sobrien bfd *dynobj; 16260484Sobrien 16360484Sobrien /* Number of fixups. */ 16460484Sobrien size_t fixup_count; 16560484Sobrien 16660484Sobrien /* Number of builtin fixups. */ 16760484Sobrien size_t local_builtins; 16860484Sobrien 16960484Sobrien /* List of fixups. */ 17060484Sobrien struct fixup *fixup_list; 17160484Sobrien}; 17260484Sobrien 17360484Sobrienstatic struct bfd_hash_entry *linux_link_hash_newfunc 17460484Sobrien PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); 17560484Sobrienstatic struct bfd_link_hash_table *linux_link_hash_table_create 17660484Sobrien PARAMS ((bfd *)); 17760484Sobrienstatic struct fixup *new_fixup 17860484Sobrien PARAMS ((struct bfd_link_info *, struct linux_link_hash_entry *, 179130561Sobrien bfd_vma, int)); 180130561Sobrienstatic bfd_boolean linux_link_create_dynamic_sections 18160484Sobrien PARAMS ((bfd *, struct bfd_link_info *)); 182130561Sobrienstatic bfd_boolean linux_add_one_symbol 18360484Sobrien PARAMS ((struct bfd_link_info *, bfd *, const char *, flagword, asection *, 184130561Sobrien bfd_vma, const char *, bfd_boolean, bfd_boolean, 185130561Sobrien struct bfd_link_hash_entry **)); 186130561Sobrienstatic bfd_boolean linux_tally_symbols 18760484Sobrien PARAMS ((struct linux_link_hash_entry *, PTR)); 188130561Sobrienstatic bfd_boolean linux_finish_dynamic_link 18960484Sobrien PARAMS ((bfd *, struct bfd_link_info *)); 19060484Sobrien 19160484Sobrien/* Routine to create an entry in an Linux link hash table. */ 19260484Sobrien 19360484Sobrienstatic struct bfd_hash_entry * 19460484Sobrienlinux_link_hash_newfunc (entry, table, string) 19560484Sobrien struct bfd_hash_entry *entry; 19660484Sobrien struct bfd_hash_table *table; 19760484Sobrien const char *string; 19860484Sobrien{ 19960484Sobrien struct linux_link_hash_entry *ret = (struct linux_link_hash_entry *) entry; 20060484Sobrien 20160484Sobrien /* Allocate the structure if it has not already been allocated by a 20260484Sobrien subclass. */ 20360484Sobrien if (ret == (struct linux_link_hash_entry *) NULL) 20460484Sobrien ret = ((struct linux_link_hash_entry *) 205130561Sobrien bfd_hash_allocate (table, sizeof (struct linux_link_hash_entry))); 20660484Sobrien if (ret == NULL) 20760484Sobrien return (struct bfd_hash_entry *) ret; 20860484Sobrien 20960484Sobrien /* Call the allocation method of the superclass. */ 21060484Sobrien ret = ((struct linux_link_hash_entry *) 211130561Sobrien NAME(aout,link_hash_newfunc) ((struct bfd_hash_entry *) ret, 212130561Sobrien table, string)); 21360484Sobrien if (ret != NULL) 21460484Sobrien { 21560484Sobrien /* Set local fields; there aren't any. */ 21660484Sobrien } 21760484Sobrien 21860484Sobrien return (struct bfd_hash_entry *) ret; 21960484Sobrien} 22060484Sobrien 22160484Sobrien/* Create a Linux link hash table. */ 22260484Sobrien 22360484Sobrienstatic struct bfd_link_hash_table * 22460484Sobrienlinux_link_hash_table_create (abfd) 22560484Sobrien bfd *abfd; 22660484Sobrien{ 22760484Sobrien struct linux_link_hash_table *ret; 22889857Sobrien bfd_size_type amt = sizeof (struct linux_link_hash_table); 22960484Sobrien 230104834Sobrien ret = (struct linux_link_hash_table *) bfd_malloc (amt); 23160484Sobrien if (ret == (struct linux_link_hash_table *) NULL) 23260484Sobrien return (struct bfd_link_hash_table *) NULL; 233218822Sdim if (!NAME(aout,link_hash_table_init) (&ret->root, abfd, 234218822Sdim linux_link_hash_newfunc, 235218822Sdim sizeof (struct linux_link_hash_entry))) 23660484Sobrien { 23760484Sobrien free (ret); 23860484Sobrien return (struct bfd_link_hash_table *) NULL; 23960484Sobrien } 24060484Sobrien 24160484Sobrien ret->dynobj = NULL; 24260484Sobrien ret->fixup_count = 0; 24360484Sobrien ret->local_builtins = 0; 24460484Sobrien ret->fixup_list = NULL; 24560484Sobrien 24660484Sobrien return &ret->root.root; 24760484Sobrien} 24860484Sobrien 24960484Sobrien/* Look up an entry in a Linux link hash table. */ 25060484Sobrien 25160484Sobrien#define linux_link_hash_lookup(table, string, create, copy, follow) \ 25260484Sobrien ((struct linux_link_hash_entry *) \ 25360484Sobrien aout_link_hash_lookup (&(table)->root, (string), (create), (copy),\ 254130561Sobrien (follow))) 25560484Sobrien 25660484Sobrien/* Traverse a Linux link hash table. */ 25760484Sobrien 258130561Sobrien#define linux_link_hash_traverse(table, func, info) \ 259130561Sobrien (aout_link_hash_traverse \ 260130561Sobrien (&(table)->root, \ 261130561Sobrien (bfd_boolean (*) PARAMS ((struct aout_link_hash_entry *, PTR))) (func), \ 26260484Sobrien (info))) 26360484Sobrien 26460484Sobrien/* Get the Linux link hash table from the info structure. This is 26560484Sobrien just a cast. */ 26660484Sobrien 26760484Sobrien#define linux_hash_table(p) ((struct linux_link_hash_table *) ((p)->hash)) 26860484Sobrien 26960484Sobrien/* Store the information for a new fixup. */ 27060484Sobrien 27160484Sobrienstatic struct fixup * 27260484Sobriennew_fixup (info, h, value, builtin) 27360484Sobrien struct bfd_link_info *info; 27460484Sobrien struct linux_link_hash_entry *h; 27560484Sobrien bfd_vma value; 27660484Sobrien int builtin; 27760484Sobrien{ 27860484Sobrien struct fixup *f; 27960484Sobrien 28060484Sobrien f = (struct fixup *) bfd_hash_allocate (&info->hash->table, 281130561Sobrien sizeof (struct fixup)); 28260484Sobrien if (f == NULL) 28360484Sobrien return f; 28460484Sobrien f->next = linux_hash_table (info)->fixup_list; 28560484Sobrien linux_hash_table (info)->fixup_list = f; 28660484Sobrien f->h = h; 28760484Sobrien f->value = value; 28860484Sobrien f->builtin = builtin; 28960484Sobrien f->jump = 0; 29060484Sobrien ++linux_hash_table (info)->fixup_count; 29160484Sobrien return f; 29260484Sobrien} 29360484Sobrien 29460484Sobrien/* We come here once we realize that we are going to link to a shared 29560484Sobrien library. We need to create a special section that contains the 29660484Sobrien fixup table, and we ultimately need to add a pointer to this into 29760484Sobrien the set vector for SHARABLE_CONFLICTS. At this point we do not 29860484Sobrien know the size of the section, but that's OK - we just need to 29960484Sobrien create it for now. */ 30060484Sobrien 301130561Sobrienstatic bfd_boolean 30260484Sobrienlinux_link_create_dynamic_sections (abfd, info) 30360484Sobrien bfd *abfd; 30460484Sobrien struct bfd_link_info *info ATTRIBUTE_UNUSED; 30560484Sobrien{ 30660484Sobrien flagword flags; 30760484Sobrien register asection *s; 30860484Sobrien 30960484Sobrien /* Note that we set the SEC_IN_MEMORY flag. */ 31060484Sobrien flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; 31160484Sobrien 31260484Sobrien /* We choose to use the name ".linux-dynamic" for the fixup table. 313130561Sobrien Why not? */ 314218822Sdim s = bfd_make_section_with_flags (abfd, ".linux-dynamic", flags); 31560484Sobrien if (s == NULL 31660484Sobrien || ! bfd_set_section_alignment (abfd, s, 2)) 317130561Sobrien return FALSE; 318218822Sdim s->size = 0; 31960484Sobrien s->contents = 0; 32060484Sobrien 321130561Sobrien return TRUE; 32260484Sobrien} 32360484Sobrien 32460484Sobrien/* Function to add a single symbol to the linker hash table. This is 32560484Sobrien a wrapper around _bfd_generic_link_add_one_symbol which handles the 32660484Sobrien tweaking needed for dynamic linking support. */ 32760484Sobrien 328130561Sobrienstatic bfd_boolean 32960484Sobrienlinux_add_one_symbol (info, abfd, name, flags, section, value, string, 330130561Sobrien copy, collect, hashp) 33160484Sobrien struct bfd_link_info *info; 33260484Sobrien bfd *abfd; 33360484Sobrien const char *name; 33460484Sobrien flagword flags; 33560484Sobrien asection *section; 33660484Sobrien bfd_vma value; 33760484Sobrien const char *string; 338130561Sobrien bfd_boolean copy; 339130561Sobrien bfd_boolean collect; 34060484Sobrien struct bfd_link_hash_entry **hashp; 34160484Sobrien{ 34260484Sobrien struct linux_link_hash_entry *h; 343130561Sobrien bfd_boolean insert; 34460484Sobrien 34560484Sobrien /* Look up and see if we already have this symbol in the hash table. 34660484Sobrien If we do, and the defining entry is from a shared library, we 34760484Sobrien need to create the dynamic sections. 34860484Sobrien 34960484Sobrien FIXME: What if abfd->xvec != info->hash->creator? We may want to 35060484Sobrien be able to link Linux a.out and ELF objects together, but serious 35160484Sobrien confusion is possible. */ 35260484Sobrien 353130561Sobrien insert = FALSE; 35460484Sobrien 355130561Sobrien if (! info->relocatable 35660484Sobrien && linux_hash_table (info)->dynobj == NULL 35760484Sobrien && strcmp (name, SHARABLE_CONFLICTS) == 0 35860484Sobrien && (flags & BSF_CONSTRUCTOR) != 0 35960484Sobrien && abfd->xvec == info->hash->creator) 36060484Sobrien { 36160484Sobrien if (! linux_link_create_dynamic_sections (abfd, info)) 362130561Sobrien return FALSE; 36360484Sobrien linux_hash_table (info)->dynobj = abfd; 364130561Sobrien insert = TRUE; 36560484Sobrien } 36660484Sobrien 36760484Sobrien if (bfd_is_abs_section (section) 36860484Sobrien && abfd->xvec == info->hash->creator) 36960484Sobrien { 370130561Sobrien h = linux_link_hash_lookup (linux_hash_table (info), name, FALSE, 371130561Sobrien FALSE, FALSE); 37260484Sobrien if (h != NULL 373130561Sobrien && (h->root.root.type == bfd_link_hash_defined 374130561Sobrien || h->root.root.type == bfd_link_hash_defweak)) 375130561Sobrien { 376130561Sobrien struct fixup *f; 37760484Sobrien 378130561Sobrien if (hashp != NULL) 379130561Sobrien *hashp = (struct bfd_link_hash_entry *) h; 38060484Sobrien 381130561Sobrien f = new_fixup (info, h, value, ! IS_PLT_SYM (name)); 382130561Sobrien if (f == NULL) 383130561Sobrien return FALSE; 384130561Sobrien f->jump = IS_PLT_SYM (name); 38560484Sobrien 386130561Sobrien return TRUE; 387130561Sobrien } 38860484Sobrien } 38960484Sobrien 39060484Sobrien /* Do the usual procedure for adding a symbol. */ 39160484Sobrien if (! _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, 392130561Sobrien value, string, copy, collect, 393130561Sobrien hashp)) 394130561Sobrien return FALSE; 39560484Sobrien 39660484Sobrien /* Insert a pointer to our table in the set vector. The dynamic 397130561Sobrien linker requires this information. */ 39860484Sobrien if (insert) 39960484Sobrien { 40060484Sobrien asection *s; 40160484Sobrien 40260484Sobrien /* Here we do our special thing to add the pointer to the 403130561Sobrien dynamic section in the SHARABLE_CONFLICTS set vector. */ 40460484Sobrien s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, 405130561Sobrien ".linux-dynamic"); 40660484Sobrien BFD_ASSERT (s != NULL); 40760484Sobrien 40860484Sobrien if (! (_bfd_generic_link_add_one_symbol 409130561Sobrien (info, linux_hash_table (info)->dynobj, SHARABLE_CONFLICTS, 410130561Sobrien BSF_GLOBAL | BSF_CONSTRUCTOR, s, (bfd_vma) 0, NULL, 411130561Sobrien FALSE, FALSE, NULL))) 412130561Sobrien return FALSE; 41360484Sobrien } 41460484Sobrien 415130561Sobrien return TRUE; 41660484Sobrien} 41760484Sobrien 41860484Sobrien/* We will crawl the hash table and come here for every global symbol. 41960484Sobrien We will examine each entry and see if there are indications that we 42060484Sobrien need to add a fixup. There are two possible cases - one is where 42160484Sobrien you have duplicate definitions of PLT or GOT symbols - these will 42260484Sobrien have already been caught and added as "builtin" fixups. If we find 42360484Sobrien that the corresponding non PLT/GOT symbol is also present, we 42460484Sobrien convert it to a regular fixup instead. 42560484Sobrien 42660484Sobrien This function is called via linux_link_hash_traverse. */ 42760484Sobrien 428130561Sobrienstatic bfd_boolean 429218822Sdimlinux_tally_symbols (struct linux_link_hash_entry *h, void * data) 43060484Sobrien{ 43160484Sobrien struct bfd_link_info *info = (struct bfd_link_info *) data; 43260484Sobrien struct fixup *f, *f1; 43360484Sobrien int is_plt; 43460484Sobrien struct linux_link_hash_entry *h1, *h2; 435130561Sobrien bfd_boolean exists; 43660484Sobrien 43794536Sobrien if (h->root.root.type == bfd_link_hash_warning) 43894536Sobrien h = (struct linux_link_hash_entry *) h->root.root.u.i.link; 43994536Sobrien 44060484Sobrien if (h->root.root.type == bfd_link_hash_undefined 441218822Sdim && CONST_STRNEQ (h->root.root.root.string, NEEDS_SHRLIB)) 44260484Sobrien { 44360484Sobrien const char *name; 44460484Sobrien char *p; 44560484Sobrien char *alloc = NULL; 44660484Sobrien 44760484Sobrien name = h->root.root.root.string + sizeof NEEDS_SHRLIB - 1; 44860484Sobrien p = strrchr (name, '_'); 44960484Sobrien if (p != NULL) 450130561Sobrien alloc = (char *) bfd_malloc ((bfd_size_type) strlen (name) + 1); 45160484Sobrien 45260484Sobrien if (p == NULL || alloc == NULL) 453130561Sobrien (*_bfd_error_handler) (_("Output file requires shared library `%s'\n"), 454130561Sobrien name); 45560484Sobrien else 456130561Sobrien { 457130561Sobrien strcpy (alloc, name); 458130561Sobrien p = strrchr (alloc, '_'); 459130561Sobrien *p++ = '\0'; 460130561Sobrien (*_bfd_error_handler) 461130561Sobrien (_("Output file requires shared library `%s.so.%s'\n"), 462130561Sobrien alloc, p); 463130561Sobrien free (alloc); 464130561Sobrien } 46560484Sobrien 46660484Sobrien abort (); 46760484Sobrien } 46860484Sobrien 46960484Sobrien /* If this symbol is not a PLT/GOT, we do not even need to look at 47060484Sobrien it. */ 47160484Sobrien is_plt = IS_PLT_SYM (h->root.root.root.string); 47260484Sobrien 47360484Sobrien if (is_plt || IS_GOT_SYM (h->root.root.root.string)) 47460484Sobrien { 47560484Sobrien /* Look up this symbol twice. Once just as a regular lookup, 476130561Sobrien and then again following all of the indirect links until we 477130561Sobrien reach a real symbol. */ 47860484Sobrien h1 = linux_link_hash_lookup (linux_hash_table (info), 479130561Sobrien (h->root.root.root.string 480130561Sobrien + sizeof PLT_REF_PREFIX - 1), 481130561Sobrien FALSE, FALSE, TRUE); 48277298Sobrien /* h2 does not follow indirect symbols. */ 48360484Sobrien h2 = linux_link_hash_lookup (linux_hash_table (info), 484130561Sobrien (h->root.root.root.string 485130561Sobrien + sizeof PLT_REF_PREFIX - 1), 486130561Sobrien FALSE, FALSE, FALSE); 48760484Sobrien 48860484Sobrien /* The real symbol must exist but if it is also an ABS symbol, 489130561Sobrien there is no need to have a fixup. This is because they both 490130561Sobrien came from the same library. If on the other hand, we had to 491130561Sobrien use an indirect symbol to get to the real symbol, we add the 492130561Sobrien fixup anyway, since there are cases where these symbols come 493130561Sobrien from different shared libraries */ 49460484Sobrien if (h1 != NULL 495130561Sobrien && (((h1->root.root.type == bfd_link_hash_defined 496130561Sobrien || h1->root.root.type == bfd_link_hash_defweak) 497130561Sobrien && ! bfd_is_abs_section (h1->root.root.u.def.section)) 498130561Sobrien || h2->root.root.type == bfd_link_hash_indirect)) 499130561Sobrien { 500130561Sobrien /* See if there is a "builtin" fixup already present 501130561Sobrien involving this symbol. If so, convert it to a regular 502130561Sobrien fixup. In the end, this relaxes some of the requirements 503130561Sobrien about the order of performing fixups. */ 504130561Sobrien exists = FALSE; 505130561Sobrien for (f1 = linux_hash_table (info)->fixup_list; 506130561Sobrien f1 != NULL; 507130561Sobrien f1 = f1->next) 508130561Sobrien { 509130561Sobrien if ((f1->h != h && f1->h != h1) 510130561Sobrien || (! f1->builtin && ! f1->jump)) 511130561Sobrien continue; 512130561Sobrien if (f1->h == h1) 513130561Sobrien exists = TRUE; 514130561Sobrien if (! exists 515130561Sobrien && bfd_is_abs_section (h->root.root.u.def.section)) 516130561Sobrien { 517130561Sobrien f = new_fixup (info, h1, f1->h->root.root.u.def.value, 0); 518130561Sobrien f->jump = is_plt; 519130561Sobrien } 520130561Sobrien f1->h = h1; 521130561Sobrien f1->jump = is_plt; 522130561Sobrien f1->builtin = 0; 523130561Sobrien exists = TRUE; 524130561Sobrien } 525130561Sobrien if (! exists 526130561Sobrien && bfd_is_abs_section (h->root.root.u.def.section)) 527130561Sobrien { 528130561Sobrien f = new_fixup (info, h1, h->root.root.u.def.value, 0); 529130561Sobrien if (f == NULL) 530130561Sobrien { 531130561Sobrien /* FIXME: No way to return error. */ 532130561Sobrien abort (); 533130561Sobrien } 534130561Sobrien f->jump = is_plt; 535130561Sobrien } 536130561Sobrien } 53760484Sobrien 53860484Sobrien /* Quick and dirty way of stripping these symbols from the 539130561Sobrien symtab. */ 54060484Sobrien if (bfd_is_abs_section (h->root.root.u.def.section)) 541130561Sobrien h->root.written = TRUE; 54260484Sobrien } 54360484Sobrien 544130561Sobrien return TRUE; 54560484Sobrien} 54660484Sobrien 54760484Sobrien/* This is called to set the size of the .linux-dynamic section is. 54860484Sobrien It is called by the Linux linker emulation before_allocation 54960484Sobrien routine. We have finished reading all of the input files, and now 55060484Sobrien we just scan the hash tables to find out how many additional fixups 55160484Sobrien are required. */ 55260484Sobrien 553130561Sobrienbfd_boolean 55460484Sobrienbfd_sparclinux_size_dynamic_sections (output_bfd, info) 55560484Sobrien bfd *output_bfd; 55660484Sobrien struct bfd_link_info *info; 55760484Sobrien{ 55860484Sobrien struct fixup *f; 55960484Sobrien asection *s; 56060484Sobrien 56160484Sobrien if (output_bfd->xvec != &MY(vec)) 562130561Sobrien return TRUE; 56360484Sobrien 56477298Sobrien /* First find the fixups... */ 56560484Sobrien linux_link_hash_traverse (linux_hash_table (info), 566130561Sobrien linux_tally_symbols, 567130561Sobrien (PTR) info); 56860484Sobrien 56960484Sobrien /* If there are builtin fixups, leave room for a marker. This is 57060484Sobrien used by the dynamic linker so that it knows that all that follow 57160484Sobrien are builtin fixups instead of regular fixups. */ 57260484Sobrien for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next) 57360484Sobrien { 57460484Sobrien if (f->builtin) 575130561Sobrien { 576130561Sobrien ++linux_hash_table (info)->fixup_count; 577130561Sobrien ++linux_hash_table (info)->local_builtins; 578130561Sobrien break; 579130561Sobrien } 58060484Sobrien } 58160484Sobrien 58260484Sobrien if (linux_hash_table (info)->dynobj == NULL) 58360484Sobrien { 58460484Sobrien if (linux_hash_table (info)->fixup_count > 0) 585130561Sobrien abort (); 586130561Sobrien return TRUE; 58760484Sobrien } 58860484Sobrien 58960484Sobrien /* Allocate memory for our fixup table. We will fill it in later. */ 59060484Sobrien s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, 591130561Sobrien ".linux-dynamic"); 59260484Sobrien if (s != NULL) 59360484Sobrien { 594218822Sdim s->size = linux_hash_table (info)->fixup_count + 1; 595218822Sdim s->size *= 8; 596218822Sdim s->contents = (bfd_byte *) bfd_zalloc (output_bfd, s->size); 59760484Sobrien if (s->contents == NULL) 598130561Sobrien return FALSE; 59960484Sobrien } 60060484Sobrien 601130561Sobrien return TRUE; 60260484Sobrien} 60360484Sobrien 60460484Sobrien/* We come here once we are ready to actually write the fixup table to 60560484Sobrien the output file. Scan the fixup tables and so forth and generate 60660484Sobrien the stuff we need. */ 60760484Sobrien 608130561Sobrienstatic bfd_boolean 60960484Sobrienlinux_finish_dynamic_link (output_bfd, info) 61060484Sobrien bfd *output_bfd; 61160484Sobrien struct bfd_link_info *info; 61260484Sobrien{ 61360484Sobrien asection *s, *os, *is; 61460484Sobrien bfd_byte *fixup_table; 61560484Sobrien struct linux_link_hash_entry *h; 61660484Sobrien struct fixup *f; 61760484Sobrien unsigned int new_addr; 61860484Sobrien int section_offset; 61960484Sobrien unsigned int fixups_written; 62060484Sobrien 62160484Sobrien if (linux_hash_table (info)->dynobj == NULL) 622130561Sobrien return TRUE; 62360484Sobrien 62460484Sobrien s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, 625130561Sobrien ".linux-dynamic"); 62660484Sobrien BFD_ASSERT (s != NULL); 62760484Sobrien os = s->output_section; 62860484Sobrien fixups_written = 0; 62960484Sobrien 63060484Sobrien#ifdef LINUX_LINK_DEBUG 63160484Sobrien printf ("Fixup table file offset: %x VMA: %x\n", 632130561Sobrien os->filepos + s->output_offset, 633130561Sobrien os->vma + s->output_offset); 63460484Sobrien#endif 63560484Sobrien 63660484Sobrien fixup_table = s->contents; 63789857Sobrien bfd_put_32 (output_bfd, 63889857Sobrien (bfd_vma) linux_hash_table (info)->fixup_count, fixup_table); 63960484Sobrien fixup_table += 4; 64060484Sobrien 64160484Sobrien /* Fill in fixup table. */ 64260484Sobrien for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next) 64360484Sobrien { 64460484Sobrien if (f->builtin) 645130561Sobrien continue; 64660484Sobrien 64760484Sobrien if (f->h->root.root.type != bfd_link_hash_defined 648130561Sobrien && f->h->root.root.type != bfd_link_hash_defweak) 649130561Sobrien { 650130561Sobrien (*_bfd_error_handler) 651130561Sobrien (_("Symbol %s not defined for fixups\n"), 652130561Sobrien f->h->root.root.root.string); 653130561Sobrien continue; 654130561Sobrien } 65560484Sobrien 65660484Sobrien is = f->h->root.root.u.def.section; 65760484Sobrien section_offset = is->output_section->vma + is->output_offset; 65860484Sobrien new_addr = f->h->root.root.u.def.value + section_offset; 65960484Sobrien 66060484Sobrien#ifdef LINUX_LINK_DEBUG 66160484Sobrien printf ("Fixup(%d) %s: %x %x\n",f->jump, f->h->root.root.string, 662130561Sobrien new_addr, f->value); 66360484Sobrien#endif 66460484Sobrien 66560484Sobrien if (f->jump) 666130561Sobrien { 667130561Sobrien /* Relative address */ 668130561Sobrien new_addr = new_addr - (f->value + 5); 669130561Sobrien bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table); 670130561Sobrien fixup_table += 4; 671130561Sobrien bfd_put_32 (output_bfd, f->value + 1, fixup_table); 672130561Sobrien fixup_table += 4; 673130561Sobrien } 67460484Sobrien else 675130561Sobrien { 676130561Sobrien bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table); 677130561Sobrien fixup_table += 4; 678130561Sobrien bfd_put_32 (output_bfd, f->value, fixup_table); 679130561Sobrien fixup_table += 4; 680130561Sobrien } 68160484Sobrien ++fixups_written; 68260484Sobrien } 68360484Sobrien 68460484Sobrien if (linux_hash_table (info)->local_builtins != 0) 68560484Sobrien { 68660484Sobrien /* Special marker so we know to switch to the other type of fixup */ 68789857Sobrien bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table); 68860484Sobrien fixup_table += 4; 68989857Sobrien bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table); 69060484Sobrien fixup_table += 4; 69160484Sobrien ++fixups_written; 69260484Sobrien for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next) 693130561Sobrien { 694130561Sobrien if (! f->builtin) 695130561Sobrien continue; 69660484Sobrien 697130561Sobrien if (f->h->root.root.type != bfd_link_hash_defined 698130561Sobrien && f->h->root.root.type != bfd_link_hash_defweak) 699130561Sobrien { 700130561Sobrien (*_bfd_error_handler) 701130561Sobrien (_("Symbol %s not defined for fixups\n"), 702130561Sobrien f->h->root.root.root.string); 703130561Sobrien continue; 704130561Sobrien } 70560484Sobrien 706130561Sobrien is = f->h->root.root.u.def.section; 707130561Sobrien section_offset = is->output_section->vma + is->output_offset; 708130561Sobrien new_addr = f->h->root.root.u.def.value + section_offset; 70960484Sobrien 71060484Sobrien#ifdef LINUX_LINK_DEBUG 711130561Sobrien printf ("Fixup(B) %s: %x %x\n", f->h->root.root.string, 712130561Sobrien new_addr, f->value); 71360484Sobrien#endif 71460484Sobrien 715130561Sobrien bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table); 716130561Sobrien fixup_table += 4; 717130561Sobrien bfd_put_32 (output_bfd, f->value, fixup_table); 718130561Sobrien fixup_table += 4; 719130561Sobrien ++fixups_written; 720130561Sobrien } 721130561Sobrien } 72260484Sobrien 72360484Sobrien if (linux_hash_table (info)->fixup_count != fixups_written) 72460484Sobrien { 72560484Sobrien (*_bfd_error_handler) (_("Warning: fixup count mismatch\n")); 72660484Sobrien while (linux_hash_table (info)->fixup_count > fixups_written) 727130561Sobrien { 728130561Sobrien bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table); 729130561Sobrien fixup_table += 4; 730130561Sobrien bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table); 731130561Sobrien fixup_table += 4; 732130561Sobrien ++fixups_written; 733130561Sobrien } 73460484Sobrien } 73560484Sobrien 73660484Sobrien h = linux_link_hash_lookup (linux_hash_table (info), 737130561Sobrien "__BUILTIN_FIXUPS__", 738130561Sobrien FALSE, FALSE, FALSE); 73960484Sobrien 74060484Sobrien if (h != NULL 74160484Sobrien && (h->root.root.type == bfd_link_hash_defined 742130561Sobrien || h->root.root.type == bfd_link_hash_defweak)) 74360484Sobrien { 74460484Sobrien is = h->root.root.u.def.section; 74560484Sobrien section_offset = is->output_section->vma + is->output_offset; 74660484Sobrien new_addr = h->root.root.u.def.value + section_offset; 74760484Sobrien 74860484Sobrien#ifdef LINUX_LINK_DEBUG 74960484Sobrien printf ("Builtin fixup table at %x\n", new_addr); 75060484Sobrien#endif 75160484Sobrien 75289857Sobrien bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table); 75360484Sobrien } 75460484Sobrien else 75589857Sobrien bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table); 75660484Sobrien 75789857Sobrien if (bfd_seek (output_bfd, (file_ptr) (os->filepos + s->output_offset), 75889857Sobrien SEEK_SET) != 0) 759130561Sobrien return FALSE; 76060484Sobrien 761218822Sdim if (bfd_bwrite ((PTR) s->contents, s->size, output_bfd) != s->size) 762130561Sobrien return FALSE; 76360484Sobrien 764130561Sobrien return TRUE; 76560484Sobrien} 76660484Sobrien 76760484Sobrien#define MY_bfd_link_hash_table_create linux_link_hash_table_create 76860484Sobrien#define MY_add_one_symbol linux_add_one_symbol 76960484Sobrien#define MY_finish_dynamic_link linux_finish_dynamic_link 77060484Sobrien 77160484Sobrien#define MY_zmagic_contiguous 1 77260484Sobrien 77360484Sobrien#include "aout-target.h" 774