xref: /openbsd-src/gnu/usr.bin/binutils-2.17/bfd/riscix.c (revision 3d8817e467ea46cf4772788d6804dd293abfb01a)
1*3d8817e4Smiod /* BFD back-end for RISC iX (Acorn, arm) binaries.
2*3d8817e4Smiod    Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004,
3*3d8817e4Smiod    2005 Free Software Foundation, Inc.
4*3d8817e4Smiod    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
5*3d8817e4Smiod 
6*3d8817e4Smiod    This file is part of BFD, the Binary File Descriptor library.
7*3d8817e4Smiod 
8*3d8817e4Smiod    This program is free software; you can redistribute it and/or modify
9*3d8817e4Smiod    it under the terms of the GNU General Public License as published by
10*3d8817e4Smiod    the Free Software Foundation; either version 2 of the License, or
11*3d8817e4Smiod    (at your option) any later version.
12*3d8817e4Smiod 
13*3d8817e4Smiod    This program is distributed in the hope that it will be useful,
14*3d8817e4Smiod    but WITHOUT ANY WARRANTY; without even the implied warranty of
15*3d8817e4Smiod    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*3d8817e4Smiod    GNU General Public License for more details.
17*3d8817e4Smiod 
18*3d8817e4Smiod    You should have received a copy of the GNU General Public License
19*3d8817e4Smiod    along with this program; if not, write to the Free Software
20*3d8817e4Smiod    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
21*3d8817e4Smiod 
22*3d8817e4Smiod /* RISC iX overloads the MAGIC field to indicate more than just the usual
23*3d8817e4Smiod    [ZNO]MAGIC values.  Also included are squeezing information and
24*3d8817e4Smiod    shared library usage.  */
25*3d8817e4Smiod 
26*3d8817e4Smiod /* The following come from the man page.  */
27*3d8817e4Smiod #define SHLIBLEN 60
28*3d8817e4Smiod 
29*3d8817e4Smiod #define MF_IMPURE       00200
30*3d8817e4Smiod #define MF_SQUEEZED     01000
31*3d8817e4Smiod #define MF_USES_SL      02000
32*3d8817e4Smiod #define MF_IS_SL        04000
33*3d8817e4Smiod 
34*3d8817e4Smiod /* Common combinations.  */
35*3d8817e4Smiod 
36*3d8817e4Smiod /* Demand load (impure text).  */
37*3d8817e4Smiod #define IMAGIC          (MF_IMPURE | ZMAGIC)
38*3d8817e4Smiod 
39*3d8817e4Smiod /* OMAGIC with large header.
40*3d8817e4Smiod    May contain a ref to a shared lib required by the object.  */
41*3d8817e4Smiod #define SPOMAGIC        (MF_USES_SL | OMAGIC)
42*3d8817e4Smiod 
43*3d8817e4Smiod /* A reference to a shared library.
44*3d8817e4Smiod    The text portion of the object contains "overflow text" from
45*3d8817e4Smiod    the shared library to be linked in with an object.  */
46*3d8817e4Smiod #define SLOMAGIC        (MF_IS_SL | OMAGIC)
47*3d8817e4Smiod 
48*3d8817e4Smiod /* Sqeezed demand paged.
49*3d8817e4Smiod    NOTE: This interpretation of QMAGIC seems to be at variance
50*3d8817e4Smiod    with that used on other architectures.  */
51*3d8817e4Smiod #define QMAGIC          (MF_SQUEEZED | ZMAGIC)
52*3d8817e4Smiod 
53*3d8817e4Smiod /* Program which uses sl.  */
54*3d8817e4Smiod #define SPZMAGIC        (MF_USES_SL | ZMAGIC)
55*3d8817e4Smiod 
56*3d8817e4Smiod /* Sqeezed ditto.  */
57*3d8817e4Smiod #define SPQMAGIC        (MF_USES_SL | QMAGIC)
58*3d8817e4Smiod 
59*3d8817e4Smiod /* Shared lib part of prog.  */
60*3d8817e4Smiod #define SLZMAGIC        (MF_IS_SL | ZMAGIC)
61*3d8817e4Smiod 
62*3d8817e4Smiod /* Sl which uses another.  */
63*3d8817e4Smiod #define SLPZMAGIC       (MF_USES_SL | SLZMAGIC)
64*3d8817e4Smiod 
65*3d8817e4Smiod #define N_SHARED_LIB(x) ((x).a_info & MF_USES_SL)
66*3d8817e4Smiod 
67*3d8817e4Smiod /* Only a pure OMAGIC file has the minimal header.  */
68*3d8817e4Smiod #define N_TXTOFF(x)		\
69*3d8817e4Smiod  ((x).a_info == OMAGIC		\
70*3d8817e4Smiod   ? 32				\
71*3d8817e4Smiod   : (N_MAGIC(x) == ZMAGIC	\
72*3d8817e4Smiod      ? TARGET_PAGE_SIZE		\
73*3d8817e4Smiod      : 999))
74*3d8817e4Smiod 
75*3d8817e4Smiod #define N_TXTADDR(x)							     \
76*3d8817e4Smiod   (N_MAGIC(x) != ZMAGIC							     \
77*3d8817e4Smiod    ? (bfd_vma) 0 /* object file or NMAGIC */				     \
78*3d8817e4Smiod    /* Programs with shared libs are loaded at the first page after all the   \
79*3d8817e4Smiod       text segments of the shared library programs.  Without looking this    \
80*3d8817e4Smiod       up we can't know exactly what the address will be.  A reasonable guess \
81*3d8817e4Smiod       is that a_entry will be in the first page of the executable.  */	     \
82*3d8817e4Smiod    : (N_SHARED_LIB(x)							     \
83*3d8817e4Smiod       ? ((x).a_entry & ~(bfd_vma) (TARGET_PAGE_SIZE - 1))		     \
84*3d8817e4Smiod       : (bfd_vma) TEXT_START_ADDR))
85*3d8817e4Smiod 
86*3d8817e4Smiod #define N_SYMOFF(x) \
87*3d8817e4Smiod   (N_TXTOFF (x) + (x).a_text + (x).a_data + (x).a_trsize + (x).a_drsize)
88*3d8817e4Smiod 
89*3d8817e4Smiod #define N_STROFF(x) (N_SYMOFF (x) + (x).a_syms)
90*3d8817e4Smiod 
91*3d8817e4Smiod #define TEXT_START_ADDR   32768
92*3d8817e4Smiod #define TARGET_PAGE_SIZE  32768
93*3d8817e4Smiod #define SEGMENT_SIZE      TARGET_PAGE_SIZE
94*3d8817e4Smiod #define DEFAULT_ARCH      bfd_arch_arm
95*3d8817e4Smiod 
96*3d8817e4Smiod /* Do not "beautify" the CONCAT* macro args.  Traditional C will not
97*3d8817e4Smiod    remove whitespace added here, and thus will fail to concatenate
98*3d8817e4Smiod    the tokens.  */
99*3d8817e4Smiod #define MY(OP) CONCAT2 (riscix_,OP)
100*3d8817e4Smiod #define TARGETNAME "a.out-riscix"
101*3d8817e4Smiod #define N_BADMAG(x) ((((x).a_info & ~007200) != ZMAGIC) \
102*3d8817e4Smiod                   && (((x).a_info & ~006000) != OMAGIC) \
103*3d8817e4Smiod                   && ((x).a_info != NMAGIC))
104*3d8817e4Smiod #define N_MAGIC(x) ((x).a_info & ~07200)
105*3d8817e4Smiod 
106*3d8817e4Smiod #include "bfd.h"
107*3d8817e4Smiod #include "sysdep.h"
108*3d8817e4Smiod #include "libbfd.h"
109*3d8817e4Smiod 
110*3d8817e4Smiod #define WRITE_HEADERS(abfd, execp)					    \
111*3d8817e4Smiod   {									    \
112*3d8817e4Smiod     bfd_size_type text_size; /* Dummy vars.  */				    \
113*3d8817e4Smiod     file_ptr text_end;							    \
114*3d8817e4Smiod     									    \
115*3d8817e4Smiod     if (adata (abfd).magic == undecided_magic)				    \
116*3d8817e4Smiod       NAME (aout, adjust_sizes_and_vmas) (abfd, & text_size, & text_end);   \
117*3d8817e4Smiod     									    \
118*3d8817e4Smiod     execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE;	    \
119*3d8817e4Smiod     execp->a_entry = bfd_get_start_address (abfd);			    \
120*3d8817e4Smiod     									    \
121*3d8817e4Smiod     execp->a_trsize = ((obj_textsec (abfd)->reloc_count) *		    \
122*3d8817e4Smiod 		       obj_reloc_entry_size (abfd));			    \
123*3d8817e4Smiod     execp->a_drsize = ((obj_datasec (abfd)->reloc_count) *		    \
124*3d8817e4Smiod 		       obj_reloc_entry_size (abfd));			    \
125*3d8817e4Smiod     NAME (aout, swap_exec_header_out) (abfd, execp, & exec_bytes);	    \
126*3d8817e4Smiod     									    \
127*3d8817e4Smiod     if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0			    \
128*3d8817e4Smiod 	|| bfd_bwrite ((void *) & exec_bytes, (bfd_size_type) EXEC_BYTES_SIZE,  \
129*3d8817e4Smiod 		      abfd) != EXEC_BYTES_SIZE)				    \
130*3d8817e4Smiod       return FALSE;							    \
131*3d8817e4Smiod     /* Now write out reloc info, followed by syms and strings.  */	    \
132*3d8817e4Smiod 									    \
133*3d8817e4Smiod     if (bfd_get_outsymbols (abfd) != NULL			    	    \
134*3d8817e4Smiod 	&& bfd_get_symcount (abfd) != 0)				    \
135*3d8817e4Smiod       {									    \
136*3d8817e4Smiod 	if (bfd_seek (abfd, (file_ptr) (N_SYMOFF (* execp)), SEEK_SET) != 0)\
137*3d8817e4Smiod 	  return FALSE;							    \
138*3d8817e4Smiod 									    \
139*3d8817e4Smiod 	if (! NAME (aout, write_syms) (abfd))				    \
140*3d8817e4Smiod           return FALSE;							    \
141*3d8817e4Smiod 									    \
142*3d8817e4Smiod 	if (bfd_seek (abfd, (file_ptr) (N_TRELOFF (* execp)), SEEK_SET) != 0)\
143*3d8817e4Smiod 	  return FALSE;							    \
144*3d8817e4Smiod 									    \
145*3d8817e4Smiod 	if (! riscix_squirt_out_relocs (abfd, obj_textsec (abfd)))	    \
146*3d8817e4Smiod 	  return FALSE;							    \
147*3d8817e4Smiod 	if (bfd_seek (abfd, (file_ptr) (N_DRELOFF (* execp)), SEEK_SET) != 0)\
148*3d8817e4Smiod 	  return FALSE;							    \
149*3d8817e4Smiod 									    \
150*3d8817e4Smiod 	if (!NAME (aout, squirt_out_relocs) (abfd, obj_datasec (abfd)))	    \
151*3d8817e4Smiod 	  return FALSE;							    \
152*3d8817e4Smiod       }									    \
153*3d8817e4Smiod   }
154*3d8817e4Smiod 
155*3d8817e4Smiod #include "libaout.h"
156*3d8817e4Smiod #include "aout/aout64.h"
157*3d8817e4Smiod 
158*3d8817e4Smiod static bfd_reloc_status_type
riscix_fix_pcrel_26_done(bfd * abfd ATTRIBUTE_UNUSED,arelent * reloc_entry ATTRIBUTE_UNUSED,asymbol * symbol ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED,asection * input_section ATTRIBUTE_UNUSED,bfd * output_bfd ATTRIBUTE_UNUSED,char ** error_message ATTRIBUTE_UNUSED)159*3d8817e4Smiod riscix_fix_pcrel_26_done (bfd *abfd ATTRIBUTE_UNUSED,
160*3d8817e4Smiod 			  arelent *reloc_entry ATTRIBUTE_UNUSED,
161*3d8817e4Smiod 			  asymbol *symbol ATTRIBUTE_UNUSED,
162*3d8817e4Smiod 			  void * data ATTRIBUTE_UNUSED,
163*3d8817e4Smiod 			  asection *input_section ATTRIBUTE_UNUSED,
164*3d8817e4Smiod 			  bfd *output_bfd ATTRIBUTE_UNUSED,
165*3d8817e4Smiod 			  char **error_message ATTRIBUTE_UNUSED)
166*3d8817e4Smiod {
167*3d8817e4Smiod   /* This is dead simple at present.  */
168*3d8817e4Smiod   return bfd_reloc_ok;
169*3d8817e4Smiod }
170*3d8817e4Smiod 
171*3d8817e4Smiod static bfd_reloc_status_type riscix_fix_pcrel_26 (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
172*3d8817e4Smiod static const bfd_target *riscix_callback (bfd *);
173*3d8817e4Smiod 
174*3d8817e4Smiod static reloc_howto_type riscix_std_reloc_howto[] =
175*3d8817e4Smiod {
176*3d8817e4Smiod   /* Type              rs size bsz  pcrel bitpos ovrf                     sf name     part_inpl readmask  setmask    pcdone */
177*3d8817e4Smiod   HOWTO( 0,              0,  0,   8,  FALSE, 0, complain_overflow_bitfield,0,"8",         TRUE, 0x000000ff,0x000000ff, FALSE),
178*3d8817e4Smiod   HOWTO( 1,              0,  1,   16, FALSE, 0, complain_overflow_bitfield,0,"16",        TRUE, 0x0000ffff,0x0000ffff, FALSE),
179*3d8817e4Smiod   HOWTO( 2,              0,  2,   32, FALSE, 0, complain_overflow_bitfield,0,"32",        TRUE, 0xffffffff,0xffffffff, FALSE),
180*3d8817e4Smiod   HOWTO( 3,              2,  3,   26, TRUE,  0, complain_overflow_signed,  riscix_fix_pcrel_26 , "ARM26",      TRUE, 0x00ffffff,0x00ffffff, FALSE),
181*3d8817e4Smiod   HOWTO( 4,              0,  0,   8,  TRUE,  0, complain_overflow_signed,  0,"DISP8",     TRUE, 0x000000ff,0x000000ff, TRUE),
182*3d8817e4Smiod   HOWTO( 5,              0,  1,   16, TRUE,  0, complain_overflow_signed,  0,"DISP16",    TRUE, 0x0000ffff,0x0000ffff, TRUE),
183*3d8817e4Smiod   HOWTO( 6,              0,  2,   32, TRUE,  0, complain_overflow_signed,  0,"DISP32",    TRUE, 0xffffffff,0xffffffff, TRUE),
184*3d8817e4Smiod   HOWTO( 7,              2,  3,   26, FALSE, 0, complain_overflow_signed,  riscix_fix_pcrel_26_done, "ARM26D",TRUE,0x00ffffff,0x00ffffff, FALSE),
185*3d8817e4Smiod   EMPTY_HOWTO (-1),
186*3d8817e4Smiod   HOWTO( 9,              0, -1,   16, FALSE, 0, complain_overflow_bitfield,0,"NEG16",     TRUE, 0x0000ffff,0x0000ffff, FALSE),
187*3d8817e4Smiod   HOWTO( 10,              0, -2,  32, FALSE, 0, complain_overflow_bitfield,0,"NEG32",     TRUE, 0xffffffff,0xffffffff, FALSE)
188*3d8817e4Smiod };
189*3d8817e4Smiod 
190*3d8817e4Smiod #define RISCIX_TABLE_SIZE \
191*3d8817e4Smiod   (sizeof (riscix_std_reloc_howto) / sizeof (reloc_howto_type))
192*3d8817e4Smiod 
193*3d8817e4Smiod static bfd_reloc_status_type
riscix_fix_pcrel_26(bfd * abfd,arelent * reloc_entry,asymbol * symbol,void * data,asection * input_section,bfd * output_bfd,char ** error_message ATTRIBUTE_UNUSED)194*3d8817e4Smiod riscix_fix_pcrel_26 (bfd *abfd,
195*3d8817e4Smiod 		     arelent *reloc_entry,
196*3d8817e4Smiod 		     asymbol *symbol,
197*3d8817e4Smiod 		     void * data,
198*3d8817e4Smiod 		     asection *input_section,
199*3d8817e4Smiod 		     bfd *output_bfd,
200*3d8817e4Smiod 		     char **error_message ATTRIBUTE_UNUSED)
201*3d8817e4Smiod {
202*3d8817e4Smiod   bfd_vma relocation;
203*3d8817e4Smiod   bfd_size_type addr = reloc_entry->address;
204*3d8817e4Smiod   long target = bfd_get_32 (abfd, (bfd_byte *) data + addr);
205*3d8817e4Smiod   bfd_reloc_status_type flag = bfd_reloc_ok;
206*3d8817e4Smiod 
207*3d8817e4Smiod   /* If this is an undefined symbol, return error.  */
208*3d8817e4Smiod   if (symbol->section == &bfd_und_section
209*3d8817e4Smiod       && (symbol->flags & BSF_WEAK) == 0)
210*3d8817e4Smiod     return output_bfd ? bfd_reloc_continue : bfd_reloc_undefined;
211*3d8817e4Smiod 
212*3d8817e4Smiod   /* If the sections are different, and we are doing a partial relocation,
213*3d8817e4Smiod      just ignore it for now.  */
214*3d8817e4Smiod   if (symbol->section->name != input_section->name
215*3d8817e4Smiod       && output_bfd != NULL)
216*3d8817e4Smiod     return bfd_reloc_continue;
217*3d8817e4Smiod 
218*3d8817e4Smiod   relocation = (target & 0x00ffffff) << 2;
219*3d8817e4Smiod   relocation = (relocation ^ 0x02000000) - 0x02000000; /* Sign extend.  */
220*3d8817e4Smiod   relocation += symbol->value;
221*3d8817e4Smiod   relocation += symbol->section->output_section->vma;
222*3d8817e4Smiod   relocation += symbol->section->output_offset;
223*3d8817e4Smiod   relocation += reloc_entry->addend;
224*3d8817e4Smiod   relocation -= input_section->output_section->vma;
225*3d8817e4Smiod   relocation -= input_section->output_offset;
226*3d8817e4Smiod   relocation -= addr;
227*3d8817e4Smiod   if (relocation & 3)
228*3d8817e4Smiod     return bfd_reloc_overflow;
229*3d8817e4Smiod 
230*3d8817e4Smiod   /* Check for overflow.  */
231*3d8817e4Smiod   if (relocation & 0x02000000)
232*3d8817e4Smiod     {
233*3d8817e4Smiod       if ((relocation & ~ (bfd_vma) 0x03ffffff) != ~ (bfd_vma) 0x03ffffff)
234*3d8817e4Smiod 	flag = bfd_reloc_overflow;
235*3d8817e4Smiod     }
236*3d8817e4Smiod   else if (relocation & ~ (bfd_vma) 0x03ffffff)
237*3d8817e4Smiod     flag = bfd_reloc_overflow;
238*3d8817e4Smiod 
239*3d8817e4Smiod   target &= ~0x00ffffff;
240*3d8817e4Smiod   target |= (relocation >> 2) & 0x00ffffff;
241*3d8817e4Smiod   bfd_put_32 (abfd, (bfd_vma) target, (bfd_byte *) data + addr);
242*3d8817e4Smiod 
243*3d8817e4Smiod   /* Now the ARM magic... Change the reloc type so that it is marked as done.
244*3d8817e4Smiod      Strictly this is only necessary if we are doing a partial relocation.  */
245*3d8817e4Smiod   reloc_entry->howto = &riscix_std_reloc_howto[7];
246*3d8817e4Smiod 
247*3d8817e4Smiod   return flag;
248*3d8817e4Smiod }
249*3d8817e4Smiod 
250*3d8817e4Smiod static reloc_howto_type *
riscix_reloc_type_lookup(bfd * abfd,bfd_reloc_code_real_type code)251*3d8817e4Smiod riscix_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code)
252*3d8817e4Smiod {
253*3d8817e4Smiod #define ASTD(i,j)       case i: return &riscix_std_reloc_howto[j]
254*3d8817e4Smiod   if (code == BFD_RELOC_CTOR)
255*3d8817e4Smiod     switch (bfd_get_arch_info (abfd)->bits_per_address)
256*3d8817e4Smiod       {
257*3d8817e4Smiod       case 32:
258*3d8817e4Smiod         code = BFD_RELOC_32;
259*3d8817e4Smiod         break;
260*3d8817e4Smiod       default:
261*3d8817e4Smiod 	return NULL;
262*3d8817e4Smiod       }
263*3d8817e4Smiod 
264*3d8817e4Smiod   switch (code)
265*3d8817e4Smiod     {
266*3d8817e4Smiod       ASTD (BFD_RELOC_16, 1);
267*3d8817e4Smiod       ASTD (BFD_RELOC_32, 2);
268*3d8817e4Smiod       ASTD (BFD_RELOC_ARM_PCREL_BRANCH, 3);
269*3d8817e4Smiod       ASTD (BFD_RELOC_8_PCREL, 4);
270*3d8817e4Smiod       ASTD (BFD_RELOC_16_PCREL, 5);
271*3d8817e4Smiod       ASTD (BFD_RELOC_32_PCREL, 6);
272*3d8817e4Smiod     default:
273*3d8817e4Smiod       return NULL;
274*3d8817e4Smiod     }
275*3d8817e4Smiod }
276*3d8817e4Smiod 
277*3d8817e4Smiod #define MY_bfd_link_hash_table_create  _bfd_generic_link_hash_table_create
278*3d8817e4Smiod #define MY_bfd_link_add_symbols        _bfd_generic_link_add_symbols
279*3d8817e4Smiod #define MY_final_link_callback         should_not_be_used
280*3d8817e4Smiod #define MY_bfd_final_link              _bfd_generic_final_link
281*3d8817e4Smiod 
282*3d8817e4Smiod #define MY_bfd_reloc_type_lookup       riscix_reloc_type_lookup
283*3d8817e4Smiod #define MY_canonicalize_reloc          riscix_canonicalize_reloc
284*3d8817e4Smiod #define MY_object_p                    riscix_object_p
285*3d8817e4Smiod 
286*3d8817e4Smiod static void
riscix_swap_std_reloc_out(bfd * abfd,arelent * g,struct reloc_std_external * natptr)287*3d8817e4Smiod riscix_swap_std_reloc_out (bfd *abfd,
288*3d8817e4Smiod 			   arelent *g,
289*3d8817e4Smiod 			   struct reloc_std_external *natptr)
290*3d8817e4Smiod {
291*3d8817e4Smiod   int r_index;
292*3d8817e4Smiod   asymbol *sym = *(g->sym_ptr_ptr);
293*3d8817e4Smiod   int r_extern;
294*3d8817e4Smiod   int r_length;
295*3d8817e4Smiod   int r_pcrel;
296*3d8817e4Smiod   int r_neg = 0;	/* Negative relocs use the BASEREL bit.  */
297*3d8817e4Smiod   asection *output_section = sym->section->output_section;
298*3d8817e4Smiod 
299*3d8817e4Smiod   PUT_WORD(abfd, g->address, natptr->r_address);
300*3d8817e4Smiod 
301*3d8817e4Smiod   r_length = g->howto->size ;   /* Size as a power of two.  */
302*3d8817e4Smiod   if (r_length < 0)
303*3d8817e4Smiod     {
304*3d8817e4Smiod       r_length = -r_length;
305*3d8817e4Smiod       r_neg = 1;
306*3d8817e4Smiod     }
307*3d8817e4Smiod 
308*3d8817e4Smiod   r_pcrel  = (int) g->howto->pc_relative; /* Relative to PC?  */
309*3d8817e4Smiod 
310*3d8817e4Smiod   /* For RISC iX, in pc-relative relocs the r_pcrel bit means that the
311*3d8817e4Smiod      relocation has been done already (Only for the 26-bit one I think)?  */
312*3d8817e4Smiod   if (r_length == 3)
313*3d8817e4Smiod     r_pcrel = r_pcrel ? 0 : 1;
314*3d8817e4Smiod 
315*3d8817e4Smiod   /* Name was clobbered by aout_write_syms to be symbol index.  */
316*3d8817e4Smiod 
317*3d8817e4Smiod   /* If this relocation is relative to a symbol then set the
318*3d8817e4Smiod      r_index to the symbols index, and the r_extern bit.
319*3d8817e4Smiod 
320*3d8817e4Smiod      Absolute symbols can come in in two ways, either as an offset
321*3d8817e4Smiod      from the abs section, or as a symbol which has an abs value.
322*3d8817e4Smiod      check for that here.  */
323*3d8817e4Smiod 
324*3d8817e4Smiod   if (bfd_is_com_section (output_section)
325*3d8817e4Smiod       || output_section == & bfd_abs_section
326*3d8817e4Smiod       || output_section == & bfd_und_section)
327*3d8817e4Smiod     {
328*3d8817e4Smiod       if (bfd_abs_section.symbol == sym)
329*3d8817e4Smiod 	{
330*3d8817e4Smiod 	  /* Whoops, looked like an abs symbol, but is really an offset
331*3d8817e4Smiod 	     from the abs section.  */
332*3d8817e4Smiod 	  r_index = 0;
333*3d8817e4Smiod 	  r_extern = 0;
334*3d8817e4Smiod 	}
335*3d8817e4Smiod       else
336*3d8817e4Smiod 	{
337*3d8817e4Smiod 	  /* Fill in symbol.  */
338*3d8817e4Smiod 	  r_extern = 1;
339*3d8817e4Smiod 	  r_index = (*g->sym_ptr_ptr)->udata.i;
340*3d8817e4Smiod 	}
341*3d8817e4Smiod     }
342*3d8817e4Smiod   else
343*3d8817e4Smiod     {
344*3d8817e4Smiod       /* Just an ordinary section.  */
345*3d8817e4Smiod       r_extern = 0;
346*3d8817e4Smiod       r_index  = output_section->target_index;
347*3d8817e4Smiod     }
348*3d8817e4Smiod 
349*3d8817e4Smiod   /* Now the fun stuff.  */
350*3d8817e4Smiod   if (bfd_header_big_endian (abfd))
351*3d8817e4Smiod     {
352*3d8817e4Smiod       natptr->r_index[0] = r_index >> 16;
353*3d8817e4Smiod       natptr->r_index[1] = r_index >> 8;
354*3d8817e4Smiod       natptr->r_index[2] = r_index;
355*3d8817e4Smiod       natptr->r_type[0] =
356*3d8817e4Smiod 	(  (r_extern ?   RELOC_STD_BITS_EXTERN_BIG: 0)
357*3d8817e4Smiod 	 | (r_pcrel  ?   RELOC_STD_BITS_PCREL_BIG: 0)
358*3d8817e4Smiod 	 | (r_neg    ?   RELOC_STD_BITS_BASEREL_BIG: 0)
359*3d8817e4Smiod 	 | (r_length <<  RELOC_STD_BITS_LENGTH_SH_BIG));
360*3d8817e4Smiod     }
361*3d8817e4Smiod   else
362*3d8817e4Smiod     {
363*3d8817e4Smiod       natptr->r_index[2] = r_index >> 16;
364*3d8817e4Smiod       natptr->r_index[1] = r_index >> 8;
365*3d8817e4Smiod       natptr->r_index[0] = r_index;
366*3d8817e4Smiod       natptr->r_type[0] =
367*3d8817e4Smiod 	(  (r_extern ?   RELOC_STD_BITS_EXTERN_LITTLE: 0)
368*3d8817e4Smiod 	 | (r_pcrel  ?   RELOC_STD_BITS_PCREL_LITTLE: 0)
369*3d8817e4Smiod 	 | (r_neg    ?   RELOC_STD_BITS_BASEREL_LITTLE: 0)
370*3d8817e4Smiod 	 | (r_length <<  RELOC_STD_BITS_LENGTH_SH_LITTLE));
371*3d8817e4Smiod     }
372*3d8817e4Smiod }
373*3d8817e4Smiod 
374*3d8817e4Smiod static bfd_boolean
riscix_squirt_out_relocs(bfd * abfd,asection * section)375*3d8817e4Smiod riscix_squirt_out_relocs (bfd *abfd, asection *section)
376*3d8817e4Smiod {
377*3d8817e4Smiod   arelent **generic;
378*3d8817e4Smiod   unsigned char *native, *natptr;
379*3d8817e4Smiod   size_t each_size;
380*3d8817e4Smiod   unsigned int count = section->reloc_count;
381*3d8817e4Smiod   bfd_size_type natsize;
382*3d8817e4Smiod 
383*3d8817e4Smiod   if (count == 0)
384*3d8817e4Smiod     return TRUE;
385*3d8817e4Smiod 
386*3d8817e4Smiod   each_size = obj_reloc_entry_size (abfd);
387*3d8817e4Smiod   natsize = each_size;
388*3d8817e4Smiod   natsize *= count;
389*3d8817e4Smiod   native = bfd_zalloc (abfd, natsize);
390*3d8817e4Smiod   if (!native)
391*3d8817e4Smiod     return FALSE;
392*3d8817e4Smiod 
393*3d8817e4Smiod   generic = section->orelocation;
394*3d8817e4Smiod 
395*3d8817e4Smiod   for (natptr = native;
396*3d8817e4Smiod        count != 0;
397*3d8817e4Smiod        --count, natptr += each_size, ++generic)
398*3d8817e4Smiod     riscix_swap_std_reloc_out (abfd, *generic,
399*3d8817e4Smiod 			       (struct reloc_std_external *) natptr);
400*3d8817e4Smiod 
401*3d8817e4Smiod   if (bfd_bwrite ((void *) native, natsize, abfd) != natsize)
402*3d8817e4Smiod     {
403*3d8817e4Smiod       bfd_release (abfd, native);
404*3d8817e4Smiod       return FALSE;
405*3d8817e4Smiod     }
406*3d8817e4Smiod 
407*3d8817e4Smiod   bfd_release (abfd, native);
408*3d8817e4Smiod   return TRUE;
409*3d8817e4Smiod }
410*3d8817e4Smiod 
411*3d8817e4Smiod /* This is just like the standard aoutx.h version but we need to do our
412*3d8817e4Smiod    own mapping of external reloc type values to howto entries.  */
413*3d8817e4Smiod 
414*3d8817e4Smiod static long
MY(canonicalize_reloc)415*3d8817e4Smiod MY (canonicalize_reloc) (bfd *abfd,
416*3d8817e4Smiod 			 sec_ptr section,
417*3d8817e4Smiod 			 arelent **relptr,
418*3d8817e4Smiod 			 asymbol **symbols)
419*3d8817e4Smiod {
420*3d8817e4Smiod   arelent *tblptr = section->relocation;
421*3d8817e4Smiod   unsigned int count, c;
422*3d8817e4Smiod   extern reloc_howto_type NAME (aout, std_howto_table)[];
423*3d8817e4Smiod 
424*3d8817e4Smiod   /* If we have already read in the relocation table, return the values.  */
425*3d8817e4Smiod   if (section->flags & SEC_CONSTRUCTOR)
426*3d8817e4Smiod     {
427*3d8817e4Smiod       arelent_chain *chain = section->constructor_chain;
428*3d8817e4Smiod 
429*3d8817e4Smiod       for (count = 0; count < section->reloc_count; count++)
430*3d8817e4Smiod 	{
431*3d8817e4Smiod 	  *relptr++ = &chain->relent;
432*3d8817e4Smiod 	  chain = chain->next;
433*3d8817e4Smiod 	}
434*3d8817e4Smiod       *relptr = 0;
435*3d8817e4Smiod       return section->reloc_count;
436*3d8817e4Smiod     }
437*3d8817e4Smiod 
438*3d8817e4Smiod   if (tblptr && section->reloc_count)
439*3d8817e4Smiod     {
440*3d8817e4Smiod       for (count = 0; count++ < section->reloc_count;)
441*3d8817e4Smiod 	*relptr++ = tblptr++;
442*3d8817e4Smiod       *relptr = 0;
443*3d8817e4Smiod       return section->reloc_count;
444*3d8817e4Smiod     }
445*3d8817e4Smiod 
446*3d8817e4Smiod   if (!NAME (aout, slurp_reloc_table) (abfd, section, symbols))
447*3d8817e4Smiod     return -1;
448*3d8817e4Smiod   tblptr = section->relocation;
449*3d8817e4Smiod 
450*3d8817e4Smiod   /* Fix up howto entries.  */
451*3d8817e4Smiod   for (count = 0; count++ < section->reloc_count;)
452*3d8817e4Smiod     {
453*3d8817e4Smiod       c = tblptr->howto - NAME(aout,std_howto_table);
454*3d8817e4Smiod       BFD_ASSERT (c < RISCIX_TABLE_SIZE);
455*3d8817e4Smiod       tblptr->howto = &riscix_std_reloc_howto[c];
456*3d8817e4Smiod 
457*3d8817e4Smiod       *relptr++ = tblptr++;
458*3d8817e4Smiod     }
459*3d8817e4Smiod   *relptr = 0;
460*3d8817e4Smiod   return section->reloc_count;
461*3d8817e4Smiod }
462*3d8817e4Smiod 
463*3d8817e4Smiod /* This is the same as NAME(aout,some_aout_object_p), but has different
464*3d8817e4Smiod    expansions of the macro definitions.  */
465*3d8817e4Smiod 
466*3d8817e4Smiod static const bfd_target *
riscix_some_aout_object_p(bfd * abfd,struct internal_exec * execp,const bfd_target * (* callback_to_real_object_p)(bfd *))467*3d8817e4Smiod riscix_some_aout_object_p (bfd *abfd,
468*3d8817e4Smiod 			   struct internal_exec *execp,
469*3d8817e4Smiod 			   const bfd_target *(*callback_to_real_object_p) (bfd *))
470*3d8817e4Smiod {
471*3d8817e4Smiod   struct aout_data_struct *rawptr, *oldrawptr;
472*3d8817e4Smiod   const bfd_target *result;
473*3d8817e4Smiod   bfd_size_type amt = sizeof (struct aout_data_struct);
474*3d8817e4Smiod 
475*3d8817e4Smiod   rawptr = bfd_zalloc (abfd, amt);
476*3d8817e4Smiod 
477*3d8817e4Smiod   if (rawptr == NULL)
478*3d8817e4Smiod     return NULL;
479*3d8817e4Smiod 
480*3d8817e4Smiod   oldrawptr = abfd->tdata.aout_data;
481*3d8817e4Smiod   abfd->tdata.aout_data = rawptr;
482*3d8817e4Smiod 
483*3d8817e4Smiod   /* Copy the contents of the old tdata struct.
484*3d8817e4Smiod      In particular, we want the subformat, since for hpux it was set in
485*3d8817e4Smiod      hp300hpux.c:swap_exec_header_in and will be used in
486*3d8817e4Smiod      hp300hpux.c:callback.  */
487*3d8817e4Smiod   if (oldrawptr != NULL)
488*3d8817e4Smiod     *abfd->tdata.aout_data = *oldrawptr;
489*3d8817e4Smiod 
490*3d8817e4Smiod   abfd->tdata.aout_data->a.hdr = &rawptr->e;
491*3d8817e4Smiod   /* Copy in the internal_exec struct.  */
492*3d8817e4Smiod   *(abfd->tdata.aout_data->a.hdr) = *execp;
493*3d8817e4Smiod   execp = abfd->tdata.aout_data->a.hdr;
494*3d8817e4Smiod 
495*3d8817e4Smiod   /* Set the file flags.  */
496*3d8817e4Smiod   abfd->flags = BFD_NO_FLAGS;
497*3d8817e4Smiod   if (execp->a_drsize || execp->a_trsize)
498*3d8817e4Smiod     abfd->flags |= HAS_RELOC;
499*3d8817e4Smiod   /* Setting of EXEC_P has been deferred to the bottom of this function.  */
500*3d8817e4Smiod   if (execp->a_syms)
501*3d8817e4Smiod     abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS;
502*3d8817e4Smiod   if (N_DYNAMIC(*execp))
503*3d8817e4Smiod     abfd->flags |= DYNAMIC;
504*3d8817e4Smiod 
505*3d8817e4Smiod  /* Squeezed files aren't supported (yet)!  */
506*3d8817e4Smiod   if ((execp->a_info & MF_SQUEEZED) != 0)
507*3d8817e4Smiod     {
508*3d8817e4Smiod       bfd_set_error (bfd_error_wrong_format);
509*3d8817e4Smiod       return NULL;
510*3d8817e4Smiod     }
511*3d8817e4Smiod   else if ((execp->a_info & MF_IS_SL) != 0)
512*3d8817e4Smiod     {
513*3d8817e4Smiod       /* Nor are shared libraries.  */
514*3d8817e4Smiod       bfd_set_error (bfd_error_wrong_format);
515*3d8817e4Smiod       return NULL;
516*3d8817e4Smiod     }
517*3d8817e4Smiod   else if (N_MAGIC (*execp) == ZMAGIC)
518*3d8817e4Smiod     {
519*3d8817e4Smiod       abfd->flags |= D_PAGED | WP_TEXT;
520*3d8817e4Smiod       adata (abfd).magic = z_magic;
521*3d8817e4Smiod     }
522*3d8817e4Smiod   else if (N_MAGIC (*execp) == NMAGIC)
523*3d8817e4Smiod     {
524*3d8817e4Smiod       abfd->flags |= WP_TEXT;
525*3d8817e4Smiod       adata (abfd).magic = n_magic;
526*3d8817e4Smiod     }
527*3d8817e4Smiod   else if (N_MAGIC (*execp) == OMAGIC)
528*3d8817e4Smiod     adata (abfd).magic = o_magic;
529*3d8817e4Smiod   else
530*3d8817e4Smiod     /* Should have been checked with N_BADMAG before this routine
531*3d8817e4Smiod        was called.  */
532*3d8817e4Smiod     abort ();
533*3d8817e4Smiod 
534*3d8817e4Smiod   bfd_get_start_address (abfd) = execp->a_entry;
535*3d8817e4Smiod 
536*3d8817e4Smiod   obj_aout_symbols (abfd) = NULL;
537*3d8817e4Smiod   bfd_get_symcount (abfd) = execp->a_syms / sizeof (struct external_nlist);
538*3d8817e4Smiod 
539*3d8817e4Smiod   /* The default relocation entry size is that of traditional V7 Unix.  */
540*3d8817e4Smiod   obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
541*3d8817e4Smiod 
542*3d8817e4Smiod   /* The default symbol entry size is that of traditional Unix.  */
543*3d8817e4Smiod   obj_symbol_entry_size (abfd) = EXTERNAL_NLIST_SIZE;
544*3d8817e4Smiod 
545*3d8817e4Smiod   obj_aout_external_syms (abfd) = NULL;
546*3d8817e4Smiod   obj_aout_external_strings (abfd) = NULL;
547*3d8817e4Smiod   obj_aout_sym_hashes (abfd) = NULL;
548*3d8817e4Smiod 
549*3d8817e4Smiod   if (! NAME (aout, make_sections) (abfd))
550*3d8817e4Smiod     return NULL;
551*3d8817e4Smiod 
552*3d8817e4Smiod   obj_datasec (abfd)->size = execp->a_data;
553*3d8817e4Smiod   obj_bsssec (abfd)->size = execp->a_bss;
554*3d8817e4Smiod 
555*3d8817e4Smiod   obj_textsec (abfd)->flags =
556*3d8817e4Smiod     (execp->a_trsize != 0
557*3d8817e4Smiod      ? (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_RELOC)
558*3d8817e4Smiod      : (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS));
559*3d8817e4Smiod   obj_datasec (abfd)->flags =
560*3d8817e4Smiod     (execp->a_drsize != 0
561*3d8817e4Smiod      ? (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS | SEC_RELOC)
562*3d8817e4Smiod      : (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS));
563*3d8817e4Smiod   obj_bsssec (abfd)->flags = SEC_ALLOC;
564*3d8817e4Smiod 
565*3d8817e4Smiod   result = (*callback_to_real_object_p) (abfd);
566*3d8817e4Smiod 
567*3d8817e4Smiod #if defined(MACH) || defined(STAT_FOR_EXEC)
568*3d8817e4Smiod   /* The original heuristic doesn't work in some important cases. The
569*3d8817e4Smiod      a.out file has no information about the text start address. For
570*3d8817e4Smiod      files (like kernels) linked to non-standard addresses (ld -Ttext
571*3d8817e4Smiod      nnn) the entry point may not be between the default text start
572*3d8817e4Smiod      (obj_textsec(abfd)->vma) and (obj_textsec(abfd)->vma) + text size
573*3d8817e4Smiod      This is not just a mach issue. Many kernels are loaded at non
574*3d8817e4Smiod      standard addresses.  */
575*3d8817e4Smiod   {
576*3d8817e4Smiod     struct stat stat_buf;
577*3d8817e4Smiod 
578*3d8817e4Smiod     if (abfd->iostream != NULL
579*3d8817e4Smiod 	&& (abfd->flags & BFD_IN_MEMORY) == 0
580*3d8817e4Smiod         && (fstat(fileno((FILE *) (abfd->iostream)), &stat_buf) == 0)
581*3d8817e4Smiod         && ((stat_buf.st_mode & 0111) != 0))
582*3d8817e4Smiod       abfd->flags |= EXEC_P;
583*3d8817e4Smiod   }
584*3d8817e4Smiod #else /* ! MACH */
585*3d8817e4Smiod   /* Now that the segment addresses have been worked out, take a better
586*3d8817e4Smiod      guess at whether the file is executable.  If the entry point
587*3d8817e4Smiod      is within the text segment, assume it is.  (This makes files
588*3d8817e4Smiod      executable even if their entry point address is 0, as long as
589*3d8817e4Smiod      their text starts at zero.)
590*3d8817e4Smiod 
591*3d8817e4Smiod      At some point we should probably break down and stat the file and
592*3d8817e4Smiod      declare it executable if (one of) its 'x' bits are on...  */
593*3d8817e4Smiod   if ((execp->a_entry >= obj_textsec(abfd)->vma) &&
594*3d8817e4Smiod       (execp->a_entry < obj_textsec(abfd)->vma + obj_textsec(abfd)->size))
595*3d8817e4Smiod     abfd->flags |= EXEC_P;
596*3d8817e4Smiod #endif /* MACH */
597*3d8817e4Smiod   if (result == NULL)
598*3d8817e4Smiod     {
599*3d8817e4Smiod       free (rawptr);
600*3d8817e4Smiod       abfd->tdata.aout_data = oldrawptr;
601*3d8817e4Smiod     }
602*3d8817e4Smiod   return result;
603*3d8817e4Smiod }
604*3d8817e4Smiod 
605*3d8817e4Smiod static const bfd_target *
MY(object_p)606*3d8817e4Smiod MY (object_p) (bfd *abfd)
607*3d8817e4Smiod {
608*3d8817e4Smiod   struct external_exec exec_bytes;      /* Raw exec header from file.  */
609*3d8817e4Smiod   struct internal_exec exec;            /* Cleaned-up exec header.  */
610*3d8817e4Smiod   const bfd_target *target;
611*3d8817e4Smiod 
612*3d8817e4Smiod   if (bfd_bread ((void *) &exec_bytes, (bfd_size_type) EXEC_BYTES_SIZE, abfd)
613*3d8817e4Smiod       != EXEC_BYTES_SIZE)
614*3d8817e4Smiod     {
615*3d8817e4Smiod       if (bfd_get_error () != bfd_error_system_call)
616*3d8817e4Smiod 	bfd_set_error (bfd_error_wrong_format);
617*3d8817e4Smiod       return NULL;
618*3d8817e4Smiod     }
619*3d8817e4Smiod 
620*3d8817e4Smiod   exec.a_info = H_GET_32 (abfd, exec_bytes.e_info);
621*3d8817e4Smiod 
622*3d8817e4Smiod   if (N_BADMAG (exec))
623*3d8817e4Smiod     return NULL;
624*3d8817e4Smiod 
625*3d8817e4Smiod #ifdef MACHTYPE_OK
626*3d8817e4Smiod   if (!(MACHTYPE_OK (N_MACHTYPE (exec))))
627*3d8817e4Smiod     return NULL;
628*3d8817e4Smiod #endif
629*3d8817e4Smiod 
630*3d8817e4Smiod   NAME (aout, swap_exec_header_in) (abfd, & exec_bytes, & exec);
631*3d8817e4Smiod 
632*3d8817e4Smiod   target = riscix_some_aout_object_p (abfd, & exec, MY (callback));
633*3d8817e4Smiod 
634*3d8817e4Smiod   return target;
635*3d8817e4Smiod }
636*3d8817e4Smiod 
637*3d8817e4Smiod #include "aout-target.h"
638