1213274Srpaulo/* BFD back-end for AMD 64 COFF files.
2213274Srpaulo   Copyright 2006, 2007 Free Software Foundation, Inc.
3213274Srpaulo
4213274Srpaulo   This file is part of BFD, the Binary File Descriptor library.
5213274Srpaulo
6213274Srpaulo   This program is free software; you can redistribute it and/or modify
7213274Srpaulo   it under the terms of the GNU General Public License as published by
8213274Srpaulo   the Free Software Foundation; either version 2 of the License, or
9213274Srpaulo   (at your option) any later version.
10213274Srpaulo
11213274Srpaulo   This program is distributed in the hope that it will be useful,
12213274Srpaulo   but WITHOUT ANY WARRANTY; without even the implied warranty of
13213274Srpaulo   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14213274Srpaulo   GNU General Public License for more details.
15213274Srpaulo
16213274Srpaulo   You should have received a copy of the GNU General Public License
17213274Srpaulo   along with this program; if not, write to the Free Software
18213274Srpaulo   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
19213274Srpaulo
20213274Srpaulo   Written by Kai Tietz, OneVision Software GmbH&CoKg.  */
21213274Srpaulo
22213274Srpaulo#ifndef COFF_WITH_pex64
23213274Srpaulo#define COFF_WITH_pex64
24213274Srpaulo#endif
25213274Srpaulo
26213274Srpaulo#include "sysdep.h"
27213274Srpaulo#include "bfd.h"
28213274Srpaulo#include "libbfd.h"
29213274Srpaulo#include "coff/x86_64.h"
30213274Srpaulo#include "coff/internal.h"
31213274Srpaulo#include "coff/pe.h"
32213274Srpaulo#include "libcoff.h"
33213274Srpaulo#include "libiberty.h"
34213274Srpaulo
35213274Srpaulo#define BADMAG(x) AMD64BADMAG(x)
36213274Srpaulo
37213274Srpaulo#ifdef COFF_WITH_pex64
38213274Srpaulo# undef  AOUTSZ
39213274Srpaulo# define AOUTSZ		PEPAOUTSZ
40213274Srpaulo# define PEAOUTHDR	PEPAOUTHDR
41213274Srpaulo#endif
42213274Srpaulo
43213274Srpaulo#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
44213274Srpaulo
45213274Srpaulo/* The page size is a guess based on ELF.  */
46213274Srpaulo
47213274Srpaulo#define COFF_PAGE_SIZE 0x1000
48213274Srpaulo
49213274Srpaulo/* For some reason when using AMD COFF the value stored in the .text
50213274Srpaulo   section for a reference to a common symbol is the value itself plus
51213274Srpaulo   any desired offset.  Ian Taylor, Cygnus Support.  */
52213274Srpaulo
53213274Srpaulo/* If we are producing relocatable output, we need to do some
54213274Srpaulo   adjustments to the object file that are not done by the
55213274Srpaulo   bfd_perform_relocation function.  This function is called by every
56213274Srpaulo   reloc type to make any required adjustments.  */
57213274Srpaulo
58213274Srpaulostatic bfd_reloc_status_type
59213274Srpaulocoff_amd64_reloc (bfd *abfd,
60213274Srpaulo		  arelent *reloc_entry,
61213274Srpaulo		  asymbol *symbol,
62213274Srpaulo		  void * data,
63213274Srpaulo		  asection *input_section ATTRIBUTE_UNUSED,
64213274Srpaulo		  bfd *output_bfd,
65213274Srpaulo		  char **error_message ATTRIBUTE_UNUSED)
66213274Srpaulo{
67213274Srpaulo  symvalue diff;
68213274Srpaulo
69213274Srpaulo#if !defined(COFF_WITH_PE)
70213274Srpaulo  if (output_bfd == NULL)
71213274Srpaulo    return bfd_reloc_continue;
72213274Srpaulo#endif
73213274Srpaulo
74213274Srpaulo  if (bfd_is_com_section (symbol->section))
75213274Srpaulo    {
76213274Srpaulo#if !defined(COFF_WITH_PE)
77213274Srpaulo      /* We are relocating a common symbol.  The current value in the
78213274Srpaulo	 object file is ORIG + OFFSET, where ORIG is the value of the
79213274Srpaulo	 common symbol as seen by the object file when it was compiled
80213274Srpaulo	 (this may be zero if the symbol was undefined) and OFFSET is
81213274Srpaulo	 the offset into the common symbol (normally zero, but may be
82213274Srpaulo	 non-zero when referring to a field in a common structure).
83213274Srpaulo	 ORIG is the negative of reloc_entry->addend, which is set by
84213274Srpaulo	 the CALC_ADDEND macro below.  We want to replace the value in
85213274Srpaulo	 the object file with NEW + OFFSET, where NEW is the value of
86213274Srpaulo	 the common symbol which we are going to put in the final
87213274Srpaulo	 object file.  NEW is symbol->value.  */
88213274Srpaulo      diff = symbol->value + reloc_entry->addend;
89213274Srpaulo#else
90213274Srpaulo      /* In PE mode, we do not offset the common symbol.  */
91213274Srpaulo      diff = reloc_entry->addend;
92213274Srpaulo#endif
93213274Srpaulo    }
94213274Srpaulo  else
95213274Srpaulo    {
96213274Srpaulo      /* For some reason bfd_perform_relocation always effectively
97213274Srpaulo	 ignores the addend for a COFF target when producing
98213274Srpaulo	 relocatable output.  This seems to be always wrong for 386
99213274Srpaulo	 COFF, so we handle the addend here instead.  */
100213274Srpaulo#if defined(COFF_WITH_PE)
101213274Srpaulo      if (output_bfd == NULL)
102213274Srpaulo	{
103213274Srpaulo	  reloc_howto_type *howto = reloc_entry->howto;
104213274Srpaulo
105213274Srpaulo	  /* Although PC relative relocations are very similar between
106213274Srpaulo	     PE and non-PE formats, but they are off by 1 << howto->size
107213274Srpaulo	     bytes. For the external relocation, PE is very different
108213274Srpaulo	     from others. See md_apply_fix3 () in gas/config/tc-amd64.c.
109213274Srpaulo	     When we link PE and non-PE object files together to
110213274Srpaulo	     generate a non-PE executable, we have to compensate it
111213274Srpaulo	     here.  */
112213274Srpaulo	  if(howto->pc_relative && howto->pcrel_offset)
113213274Srpaulo	    diff = -(1 << howto->size);
114213274Srpaulo	  else if(symbol->flags & BSF_WEAK)
115213274Srpaulo	    diff = reloc_entry->addend - symbol->value;
116213274Srpaulo	  else
117213274Srpaulo	    diff = -reloc_entry->addend;
118213274Srpaulo	}
119213274Srpaulo      else
120213274Srpaulo#endif
121213274Srpaulo	diff = reloc_entry->addend;
122213274Srpaulo    }
123213274Srpaulo
124213274Srpaulo#if defined(COFF_WITH_PE)
125213274Srpaulo  /* FIXME: How should this case be handled?  */
126213274Srpaulo  if (reloc_entry->howto->type == R_AMD64_IMAGEBASE
127213274Srpaulo      && output_bfd != NULL
128213274Srpaulo      && bfd_get_flavour (output_bfd) == bfd_target_coff_flavour)
129213274Srpaulo    diff -= pe_data (output_bfd)->pe_opthdr.ImageBase;
130213274Srpaulo#endif
131213274Srpaulo
132213274Srpaulo#define DOIT(x) \
133213274Srpaulo  x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask))
134213274Srpaulo
135213274Srpaulo    if (diff != 0)
136213274Srpaulo      {
137213274Srpaulo	reloc_howto_type *howto = reloc_entry->howto;
138213274Srpaulo	unsigned char *addr = (unsigned char *) data + reloc_entry->address;
139213274Srpaulo
140213274Srpaulo	switch (howto->size)
141213274Srpaulo	  {
142213274Srpaulo	  case 0:
143213274Srpaulo	    {
144213274Srpaulo	      char x = bfd_get_8 (abfd, addr);
145213274Srpaulo	      DOIT (x);
146213274Srpaulo	      bfd_put_8 (abfd, x, addr);
147213274Srpaulo	    }
148213274Srpaulo	    break;
149213274Srpaulo
150213274Srpaulo	  case 1:
151213274Srpaulo	    {
152213274Srpaulo	      short x = bfd_get_16 (abfd, addr);
153213274Srpaulo	      DOIT (x);
154213274Srpaulo	      bfd_put_16 (abfd, (bfd_vma) x, addr);
155213274Srpaulo	    }
156213274Srpaulo	    break;
157213274Srpaulo
158213274Srpaulo	  case 2:
159213274Srpaulo	    {
160213274Srpaulo	      long x = bfd_get_32 (abfd, addr);
161213274Srpaulo	      DOIT (x);
162213274Srpaulo	      bfd_put_32 (abfd, (bfd_vma) x, addr);
163213274Srpaulo	    }
164213274Srpaulo	    break;
165213274Srpaulo	  case 4:
166213274Srpaulo	    {
167213274Srpaulo	      long long x = bfd_get_64 (abfd, addr);
168213274Srpaulo	      DOIT (x);
169213274Srpaulo	      bfd_put_64 (abfd, (bfd_vma) x, addr);
170213274Srpaulo	    }
171213274Srpaulo	    break;
172213274Srpaulo
173213274Srpaulo	  default:
174213274Srpaulo	    abort ();
175213274Srpaulo	  }
176213274Srpaulo      }
177213274Srpaulo
178213274Srpaulo  /* Now let bfd_perform_relocation finish everything up.  */
179213274Srpaulo  return bfd_reloc_continue;
180213274Srpaulo}
181213274Srpaulo
182213274Srpaulo#if defined(COFF_WITH_PE)
183213274Srpaulo/* Return TRUE if this relocation should appear in the output .reloc
184213274Srpaulo   section.  */
185213274Srpaulo
186213274Srpaulostatic bfd_boolean
187213274Srpauloin_reloc_p (bfd *abfd ATTRIBUTE_UNUSED, reloc_howto_type *howto)
188213274Srpaulo{
189213274Srpaulo  return ! howto->pc_relative && howto->type != R_AMD64_IMAGEBASE;
190213274Srpaulo}
191213274Srpaulo#endif /* COFF_WITH_PE */
192213274Srpaulo
193213274Srpaulo#ifndef PCRELOFFSET
194213274Srpaulo#define PCRELOFFSET TRUE
195213274Srpaulo#endif
196213274Srpaulo
197213274Srpaulostatic reloc_howto_type howto_table[] =
198213274Srpaulo{
199213274Srpaulo  EMPTY_HOWTO (0),
200213274Srpaulo  HOWTO (R_AMD64_DIR64,		/* type  1*/
201213274Srpaulo	 0,			/* rightshift */
202213274Srpaulo	 4,			/* size (0 = byte, 1 = short, 2 = long, 4 = long long) */
203213274Srpaulo	 64,			/* bitsize */
204213274Srpaulo	 FALSE,			/* pc_relative */
205213274Srpaulo	 0,			/* bitpos */
206213274Srpaulo	 complain_overflow_bitfield, /* complain_on_overflow */
207213274Srpaulo	 coff_amd64_reloc,	/* special_function */
208213274Srpaulo	 "R_X86_64_64",		/* name */
209213274Srpaulo	 TRUE,			/* partial_inplace */
210213274Srpaulo	 0xffffffffffffffffll,	/* src_mask */
211213274Srpaulo	 0xffffffffffffffffll,	/* dst_mask */
212213274Srpaulo	 TRUE),			/* pcrel_offset */
213213274Srpaulo  HOWTO (R_AMD64_DIR32,		/* type 2 */
214213274Srpaulo	 0,			/* rightshift */
215213274Srpaulo	 2,			/* size (0 = byte, 1 = short, 2 = long) */
216213274Srpaulo	 32,			/* bitsize */
217213274Srpaulo	 FALSE,			/* pc_relative */
218213274Srpaulo	 0,			/* bitpos */
219213274Srpaulo	 complain_overflow_bitfield, /* complain_on_overflow */
220213274Srpaulo	 coff_amd64_reloc,	/* special_function */
221213274Srpaulo	 "R_X86_64_32",		/* name */
222213274Srpaulo	 TRUE,			/* partial_inplace */
223213274Srpaulo	 0xffffffff,		/* src_mask */
224213274Srpaulo	 0xffffffff,		/* dst_mask */
225213274Srpaulo	 TRUE),			/* pcrel_offset */
226213274Srpaulo  /* PE IMAGE_REL_AMD64_ADDR32NB relocation (3).	*/
227213274Srpaulo  HOWTO (R_AMD64_IMAGEBASE,	/* type */
228213274Srpaulo	 0,			/* rightshift */
229213274Srpaulo	 2,			/* size (0 = byte, 1 = short, 2 = long) */
230213274Srpaulo	 32,			/* bitsize */
231213274Srpaulo	 FALSE,			/* pc_relative */
232213274Srpaulo	 0,			/* bitpos */
233213274Srpaulo	 complain_overflow_bitfield, /* complain_on_overflow */
234213274Srpaulo	 coff_amd64_reloc,	/* special_function */
235213274Srpaulo	 "rva32",		/* name */
236213274Srpaulo	 TRUE,			/* partial_inplace */
237213274Srpaulo	 0xffffffff,		/* src_mask */
238213274Srpaulo	 0xffffffff,		/* dst_mask */
239213274Srpaulo	 FALSE),		/* pcrel_offset */
240213274Srpaulo  /* 32-bit longword PC relative relocation (4).  */
241213274Srpaulo  HOWTO (R_AMD64_PCRLONG,	/* type 4 */
242213274Srpaulo	 0,			/* rightshift */
243213274Srpaulo	 2,			/* size (0 = byte, 1 = short, 2 = long) */
244213274Srpaulo	 32,			/* bitsize */
245213274Srpaulo	 TRUE,			/* pc_relative */
246213274Srpaulo	 0,			/* bitpos */
247213274Srpaulo	 complain_overflow_signed, /* complain_on_overflow */
248213274Srpaulo	 coff_amd64_reloc,	/* special_function */
249213274Srpaulo	 "R_X86_64_PC32",	/* name */
250213274Srpaulo	 TRUE,			/* partial_inplace */
251213274Srpaulo	 0xffffffff,		/* src_mask */
252213274Srpaulo	 0xffffffff,		/* dst_mask */
253213274Srpaulo	 PCRELOFFSET),		/* pcrel_offset */
254213274Srpaulo
255213274Srpaulo HOWTO (R_AMD64_PCRLONG_1,	/* type 5 */
256213274Srpaulo	 0,			/* rightshift */
257213274Srpaulo	 2,			/* size (0 = byte, 1 = short, 2 = long) */
258213274Srpaulo	 32,			/* bitsize */
259213274Srpaulo	 TRUE,			/* pc_relative */
260213274Srpaulo	 0,			/* bitpos */
261213274Srpaulo	 complain_overflow_signed, /* complain_on_overflow */
262213274Srpaulo	 coff_amd64_reloc,	/* special_function */
263213274Srpaulo	 "DISP32+1",		/* name */
264213274Srpaulo	 TRUE,			/* partial_inplace */
265213274Srpaulo	 0xffffffff,		/* src_mask */
266213274Srpaulo	 0xffffffff,		/* dst_mask */
267213274Srpaulo	 PCRELOFFSET),		/* pcrel_offset */
268213274Srpaulo HOWTO (R_AMD64_PCRLONG_2,	/* type 6 */
269213274Srpaulo	 0,			/* rightshift */
270213274Srpaulo	 2,			/* size (0 = byte, 1 = short, 2 = long) */
271213274Srpaulo	 32,			/* bitsize */
272213274Srpaulo	 TRUE,			/* pc_relative */
273213274Srpaulo	 0,			/* bitpos */
274213274Srpaulo	 complain_overflow_signed, /* complain_on_overflow */
275213274Srpaulo	 coff_amd64_reloc,	/* special_function */
276213274Srpaulo	 "DISP32+2",		/* name */
277213274Srpaulo	 TRUE,			/* partial_inplace */
278213274Srpaulo	 0xffffffff,		/* src_mask */
279213274Srpaulo	 0xffffffff,		/* dst_mask */
280213274Srpaulo	 PCRELOFFSET),		/* pcrel_offset */
281213274Srpaulo HOWTO (R_AMD64_PCRLONG_3,	/* type 7 */
282213274Srpaulo	 0,			/* rightshift */
283213274Srpaulo	 2,			/* size (0 = byte, 1 = short, 2 = long) */
284213274Srpaulo	 32,			/* bitsize */
285213274Srpaulo	 TRUE,			/* pc_relative */
286213274Srpaulo	 0,			/* bitpos */
287213274Srpaulo	 complain_overflow_signed, /* complain_on_overflow */
288213274Srpaulo	 coff_amd64_reloc,	/* special_function */
289213274Srpaulo	 "DISP32+3",		/* name */
290213274Srpaulo	 TRUE,			/* partial_inplace */
291213274Srpaulo	 0xffffffff,		/* src_mask */
292213274Srpaulo	 0xffffffff,		/* dst_mask */
293213274Srpaulo	 PCRELOFFSET),		/* pcrel_offset */
294213274Srpaulo HOWTO (R_AMD64_PCRLONG_4,	/* type 8 */
295213274Srpaulo	 0,			/* rightshift */
296213274Srpaulo	 2,			/* size (0 = byte, 1 = short, 2 = long) */
297213274Srpaulo	 32,			/* bitsize */
298213274Srpaulo	 TRUE,			/* pc_relative */
299213274Srpaulo	 0,			/* bitpos */
300213274Srpaulo	 complain_overflow_signed, /* complain_on_overflow */
301213274Srpaulo	 coff_amd64_reloc,	/* special_function */
302213274Srpaulo	 "DISP32+4",		/* name */
303213274Srpaulo	 TRUE,			/* partial_inplace */
304213274Srpaulo	 0xffffffff,		/* src_mask */
305213274Srpaulo	 0xffffffff,		/* dst_mask */
306213274Srpaulo	 PCRELOFFSET),		/* pcrel_offset */
307213274Srpaulo HOWTO (R_AMD64_PCRLONG_5,	/* type 9 */
308213274Srpaulo	 0,			/* rightshift */
309213274Srpaulo	 2,			/* size (0 = byte, 1 = short, 2 = long) */
310213274Srpaulo	 32,			/* bitsize */
311213274Srpaulo	 TRUE,			/* pc_relative */
312213274Srpaulo	 0,			/* bitpos */
313213274Srpaulo	 complain_overflow_signed, /* complain_on_overflow */
314213274Srpaulo	 coff_amd64_reloc,	/* special_function */
315213274Srpaulo	 "DISP32+5",		/* name */
316213274Srpaulo	 TRUE,			/* partial_inplace */
317213274Srpaulo	 0xffffffff,		/* src_mask */
318213274Srpaulo	 0xffffffff,		/* dst_mask */
319213274Srpaulo	 PCRELOFFSET),		/* pcrel_offset */
320213274Srpaulo  EMPTY_HOWTO (10), /* R_AMD64_SECTION 10  */
321213274Srpaulo#if defined(COFF_WITH_PE)
322213274Srpaulo  /* 32-bit longword section relative relocation (11).  */
323213274Srpaulo  HOWTO (R_AMD64_SECREL,	/* type */
324213274Srpaulo	 0,			/* rightshift */
325213274Srpaulo	 2,			/* size (0 = byte, 1 = short, 2 = long) */
326213274Srpaulo	 32,			/* bitsize */
327213274Srpaulo	 FALSE,			/* pc_relative */
328213274Srpaulo	 0,			/* bitpos */
329213274Srpaulo	 complain_overflow_bitfield, /* complain_on_overflow */
330213274Srpaulo	 coff_amd64_reloc,	/* special_function */
331213274Srpaulo	 "secrel32",		/* name */
332213274Srpaulo	 TRUE,			/* partial_inplace */
333213274Srpaulo	 0xffffffff,		/* src_mask */
334213274Srpaulo	 0xffffffff,		/* dst_mask */
335213274Srpaulo	 TRUE),			/* pcrel_offset */
336213274Srpaulo#else
337213274Srpaulo  EMPTY_HOWTO (11),
338213274Srpaulo#endif
339213274Srpaulo  EMPTY_HOWTO (12),
340213274Srpaulo  EMPTY_HOWTO (13),
341213274Srpaulo#ifndef DONT_EXTEND_AMD64
342213274Srpaulo  HOWTO (R_AMD64_PCRQUAD,
343213274Srpaulo         0,                     /* rightshift */
344213274Srpaulo         4,                     /* size (0 = byte, 1 = short, 2 = long) */
345213274Srpaulo         64,                    /* bitsize */
346213274Srpaulo         TRUE,                  /* pc_relative */
347213274Srpaulo         0,                     /* bitpos */
348213274Srpaulo         complain_overflow_signed, /* complain_on_overflow */
349213274Srpaulo         coff_amd64_reloc,      /* special_function */
350213274Srpaulo         "R_X86_64_PC64",       /* name */
351213274Srpaulo         TRUE,                  /* partial_inplace */
352213274Srpaulo         0xffffffffffffffffll,  /* src_mask */
353213274Srpaulo         0xffffffffffffffffll,  /* dst_mask */
354213274Srpaulo         PCRELOFFSET),           /* pcrel_offset */
355213274Srpaulo#else
356213274Srpaulo  EMPTY_HOWTO (14),
357213274Srpaulo#endif
358213274Srpaulo  /* Byte relocation (15).  */
359213274Srpaulo  HOWTO (R_RELBYTE,		/* type */
360213274Srpaulo	 0,			/* rightshift */
361213274Srpaulo	 0,			/* size (0 = byte, 1 = short, 2 = long) */
362213274Srpaulo	 8,			/* bitsize */
363213274Srpaulo	 FALSE,			/* pc_relative */
364213274Srpaulo	 0,			/* bitpos */
365213274Srpaulo	 complain_overflow_bitfield, /* complain_on_overflow */
366213274Srpaulo	 coff_amd64_reloc,	/* special_function */
367213274Srpaulo	 "R_X86_64_8",		/* name */
368213274Srpaulo	 TRUE,			/* partial_inplace */
369213274Srpaulo	 0x000000ff,		/* src_mask */
370213274Srpaulo	 0x000000ff,		/* dst_mask */
371213274Srpaulo	 PCRELOFFSET),		/* pcrel_offset */
372213274Srpaulo  /* 16-bit word relocation (16).  */
373213274Srpaulo  HOWTO (R_RELWORD,		/* type */
374213274Srpaulo	 0,			/* rightshift */
375213274Srpaulo	 1,			/* size (0 = byte, 1 = short, 2 = long) */
376213274Srpaulo	 16,			/* bitsize */
377213274Srpaulo	 FALSE,			/* pc_relative */
378213274Srpaulo	 0,			/* bitpos */
379213274Srpaulo	 complain_overflow_bitfield, /* complain_on_overflow */
380213274Srpaulo	 coff_amd64_reloc,	/* special_function */
381213274Srpaulo	 "R_X86_64_16",		/* name */
382213274Srpaulo	 TRUE,			/* partial_inplace */
383213274Srpaulo	 0x0000ffff,		/* src_mask */
384213274Srpaulo	 0x0000ffff,		/* dst_mask */
385213274Srpaulo	 PCRELOFFSET),		/* pcrel_offset */
386213274Srpaulo  /* 32-bit longword relocation (17).	*/
387213274Srpaulo  HOWTO (R_RELLONG,		/* type */
388213274Srpaulo	 0,			/* rightshift */
389213274Srpaulo	 2,			/* size (0 = byte, 1 = short, 2 = long) */
390213274Srpaulo	 32,			/* bitsize */
391213274Srpaulo	 FALSE,			/* pc_relative */
392213274Srpaulo	 0,			/* bitpos */
393213274Srpaulo	 complain_overflow_bitfield, /* complain_on_overflow */
394213274Srpaulo	 coff_amd64_reloc,	/* special_function */
395213274Srpaulo	 "R_X86_64_32S",	/* name */
396213274Srpaulo	 TRUE,			/* partial_inplace */
397213274Srpaulo	 0xffffffff,		/* src_mask */
398213274Srpaulo	 0xffffffff,		/* dst_mask */
399213274Srpaulo	 PCRELOFFSET),		/* pcrel_offset */
400213274Srpaulo  /* Byte PC relative relocation (18).	 */
401213274Srpaulo  HOWTO (R_PCRBYTE,		/* type */
402213274Srpaulo	 0,			/* rightshift */
403213274Srpaulo	 0,			/* size (0 = byte, 1 = short, 2 = long) */
404213274Srpaulo	 8,			/* bitsize */
405213274Srpaulo	 TRUE,			/* pc_relative */
406213274Srpaulo	 0,			/* bitpos */
407213274Srpaulo	 complain_overflow_signed, /* complain_on_overflow */
408213274Srpaulo	 coff_amd64_reloc,	/* special_function */
409213274Srpaulo	 "R_X86_64_PC8",	/* name */
410213274Srpaulo	 TRUE,			/* partial_inplace */
411213274Srpaulo	 0x000000ff,		/* src_mask */
412213274Srpaulo	 0x000000ff,		/* dst_mask */
413213274Srpaulo	 PCRELOFFSET),		/* pcrel_offset */
414213274Srpaulo  /* 16-bit word PC relative relocation (19).	*/
415213274Srpaulo  HOWTO (R_PCRWORD,		/* type */
416213274Srpaulo	 0,			/* rightshift */
417213274Srpaulo	 1,			/* size (0 = byte, 1 = short, 2 = long) */
418213274Srpaulo	 16,			/* bitsize */
419213274Srpaulo	 TRUE,			/* pc_relative */
420213274Srpaulo	 0,			/* bitpos */
421213274Srpaulo	 complain_overflow_signed, /* complain_on_overflow */
422213274Srpaulo	 coff_amd64_reloc,	/* special_function */
423213274Srpaulo	 "R_X86_64_PC16",	/* name */
424213274Srpaulo	 TRUE,			/* partial_inplace */
425213274Srpaulo	 0x0000ffff,		/* src_mask */
426213274Srpaulo	 0x0000ffff,		/* dst_mask */
427213274Srpaulo	 PCRELOFFSET),		/* pcrel_offset */
428213274Srpaulo  /* 32-bit longword PC relative relocation (20).  */
429213274Srpaulo  HOWTO (R_PCRLONG,		/* type */
430213274Srpaulo	 0,			/* rightshift */
431213274Srpaulo	 2,			/* size (0 = byte, 1 = short, 2 = long) */
432213274Srpaulo	 32,			/* bitsize */
433213274Srpaulo	 TRUE,			/* pc_relative */
434213274Srpaulo	 0,			/* bitpos */
435213274Srpaulo	 complain_overflow_signed, /* complain_on_overflow */
436213274Srpaulo	 coff_amd64_reloc,	/* special_function */
437213274Srpaulo	 "R_X86_64_PC32",	/* name */
438213274Srpaulo	 TRUE,			/* partial_inplace */
439213274Srpaulo	 0xffffffff,		/* src_mask */
440213274Srpaulo	 0xffffffff,		/* dst_mask */
441213274Srpaulo	 PCRELOFFSET)		/* pcrel_offset */
442213274Srpaulo};
443213274Srpaulo
444213274Srpaulo/* Turn a howto into a reloc  nunmber */
445213274Srpaulo
446213274Srpaulo#define SELECT_RELOC(x,howto) { x.r_type = howto->type; }
447213274Srpaulo#define I386  1			/* Customize coffcode.h */
448213274Srpaulo#define AMD64 1
449213274Srpaulo
450213274Srpaulo#define RTYPE2HOWTO(cache_ptr, dst)		\
451213274Srpaulo  ((cache_ptr)->howto =				\
452213274Srpaulo   ((dst)->r_type < ARRAY_SIZE (howto_table))	\
453213274Srpaulo    ? howto_table + (dst)->r_type		\
454213274Srpaulo    : NULL)
455213274Srpaulo
456213274Srpaulo/* For 386 COFF a STYP_NOLOAD | STYP_BSS section is part of a shared
457213274Srpaulo   library.  On some other COFF targets STYP_BSS is normally
458213274Srpaulo   STYP_NOLOAD.  */
459213274Srpaulo#define BSS_NOLOAD_IS_SHARED_LIBRARY
460213274Srpaulo
461213274Srpaulo/* Compute the addend of a reloc.  If the reloc is to a common symbol,
462213274Srpaulo   the object file contains the value of the common symbol.  By the
463213274Srpaulo   time this is called, the linker may be using a different symbol
464213274Srpaulo   from a different object file with a different value.  Therefore, we
465213274Srpaulo   hack wildly to locate the original symbol from this file so that we
466213274Srpaulo   can make the correct adjustment.  This macro sets coffsym to the
467213274Srpaulo   symbol from the original file, and uses it to set the addend value
468213274Srpaulo   correctly.  If this is not a common symbol, the usual addend
469213274Srpaulo   calculation is done, except that an additional tweak is needed for
470213274Srpaulo   PC relative relocs.
471213274Srpaulo   FIXME: This macro refers to symbols and asect; these are from the
472213274Srpaulo   calling function, not the macro arguments.  */
473213274Srpaulo
474213274Srpaulo#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr)		\
475213274Srpaulo  {								\
476213274Srpaulo    coff_symbol_type *coffsym = NULL;				\
477213274Srpaulo    								\
478213274Srpaulo    if (ptr && bfd_asymbol_bfd (ptr) != abfd)			\
479213274Srpaulo      coffsym = (obj_symbols (abfd)				\
480213274Srpaulo	         + (cache_ptr->sym_ptr_ptr - symbols));		\
481213274Srpaulo    else if (ptr)						\
482213274Srpaulo      coffsym = coff_symbol_from (abfd, ptr);			\
483213274Srpaulo    								\
484213274Srpaulo    if (coffsym != NULL						\
485213274Srpaulo	&& coffsym->native->u.syment.n_scnum == 0)		\
486213274Srpaulo      cache_ptr->addend = - coffsym->native->u.syment.n_value;	\
487213274Srpaulo    else if (ptr && bfd_asymbol_bfd (ptr) == abfd		\
488213274Srpaulo	     && ptr->section != NULL)				\
489213274Srpaulo      cache_ptr->addend = - (ptr->section->vma + ptr->value);	\
490213274Srpaulo    else							\
491213274Srpaulo      cache_ptr->addend = 0;					\
492213274Srpaulo    if (ptr && howto_table[reloc.r_type].pc_relative)		\
493213274Srpaulo      cache_ptr->addend += asect->vma;				\
494213274Srpaulo  }
495213274Srpaulo
496213274Srpaulo/* We use the special COFF backend linker.  For normal AMD64 COFF, we
497213274Srpaulo   can use the generic relocate_section routine.  For PE, we need our
498213274Srpaulo   own routine.  */
499213274Srpaulo
500213274Srpaulo#if !defined(COFF_WITH_PE)
501213274Srpaulo
502213274Srpaulo#define coff_relocate_section _bfd_coff_generic_relocate_section
503213274Srpaulo
504213274Srpaulo#else /* COFF_WITH_PE */
505213274Srpaulo
506213274Srpaulo/* The PE relocate section routine.  The only difference between this
507213274Srpaulo   and the regular routine is that we don't want to do anything for a
508213274Srpaulo   relocatable link.  */
509213274Srpaulo
510213274Srpaulostatic bfd_boolean
511213274Srpaulocoff_pe_amd64_relocate_section (bfd *output_bfd,
512213274Srpaulo				struct bfd_link_info *info,
513213274Srpaulo				bfd *input_bfd,
514213274Srpaulo				asection *input_section,
515213274Srpaulo				bfd_byte *contents,
516213274Srpaulo				struct internal_reloc *relocs,
517213274Srpaulo				struct internal_syment *syms,
518213274Srpaulo				asection **sections)
519213274Srpaulo{
520213274Srpaulo  if (info->relocatable)
521213274Srpaulo    return TRUE;
522213274Srpaulo
523213274Srpaulo  return _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,input_section, contents,relocs, syms, sections);
524213274Srpaulo}
525213274Srpaulo
526213274Srpaulo#define coff_relocate_section coff_pe_amd64_relocate_section
527213274Srpaulo
528213274Srpaulo#endif /* COFF_WITH_PE */
529213274Srpaulo
530213274Srpaulo/* Convert an rtype to howto for the COFF backend linker.  */
531213274Srpaulo
532213274Srpaulostatic reloc_howto_type *
533213274Srpaulocoff_amd64_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
534213274Srpaulo			   asection *sec,
535213274Srpaulo			   struct internal_reloc *rel,
536213274Srpaulo			   struct coff_link_hash_entry *h,
537213274Srpaulo			   struct internal_syment *sym,
538213274Srpaulo			   bfd_vma *addendp)
539213274Srpaulo{
540213274Srpaulo  reloc_howto_type *howto;
541213274Srpaulo
542213274Srpaulo  if (rel->r_type > ARRAY_SIZE (howto_table))
543213274Srpaulo    {
544213274Srpaulo      bfd_set_error (bfd_error_bad_value);
545213274Srpaulo      return NULL;
546213274Srpaulo    }
547213274Srpaulo  if (rel->r_type >= R_AMD64_PCRLONG_1 && rel->r_type <= R_AMD64_PCRLONG_5)
548213274Srpaulo    {
549213274Srpaulo      rel->r_vaddr += (bfd_vma)(rel->r_type-R_AMD64_PCRLONG);
550213274Srpaulo      rel->r_type = R_AMD64_PCRLONG;
551213274Srpaulo    }
552213274Srpaulo  howto = howto_table + rel->r_type;
553213274Srpaulo
554213274Srpaulo#if defined(COFF_WITH_PE)
555213274Srpaulo  /* Cancel out code in _bfd_coff_generic_relocate_section.  */
556213274Srpaulo  *addendp = 0;
557213274Srpaulo#endif
558213274Srpaulo
559213274Srpaulo  if (howto->pc_relative)
560213274Srpaulo    *addendp += sec->vma;
561213274Srpaulo
562213274Srpaulo  if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0)
563213274Srpaulo    {
564213274Srpaulo      /* This is a common symbol.  The section contents include the
565213274Srpaulo	 size (sym->n_value) as an addend.  The relocate_section
566213274Srpaulo	 function will be adding in the final value of the symbol.  We
567213274Srpaulo	 need to subtract out the current size in order to get the
568213274Srpaulo	 correct result.  */
569213274Srpaulo      BFD_ASSERT (h != NULL);
570213274Srpaulo
571213274Srpaulo#if !defined(COFF_WITH_PE)
572213274Srpaulo      /* I think we *do* want to bypass this.  If we don't, I have
573213274Srpaulo	 seen some data parameters get the wrong relocation address.
574213274Srpaulo	 If I link two versions with and without this section bypassed
575213274Srpaulo	 and then do a binary comparison, the addresses which are
576213274Srpaulo	 different can be looked up in the map.  The case in which
577213274Srpaulo	 this section has been bypassed has addresses which correspond
578213274Srpaulo	 to values I can find in the map.  */
579213274Srpaulo      *addendp -= sym->n_value;
580213274Srpaulo#endif
581213274Srpaulo    }
582213274Srpaulo
583213274Srpaulo#if !defined(COFF_WITH_PE)
584213274Srpaulo  /* If the output symbol is common (in which case this must be a
585213274Srpaulo     relocatable link), we need to add in the final size of the
586213274Srpaulo     common symbol.  */
587213274Srpaulo  if (h != NULL && h->root.type == bfd_link_hash_common)
588213274Srpaulo    *addendp += h->root.u.c.size;
589213274Srpaulo#endif
590213274Srpaulo
591213274Srpaulo#if defined(COFF_WITH_PE)
592213274Srpaulo  if (howto->pc_relative)
593213274Srpaulo    {
594213274Srpaulo      *addendp -= 4;
595213274Srpaulo
596213274Srpaulo      /* If the symbol is defined, then the generic code is going to
597213274Srpaulo         add back the symbol value in order to cancel out an
598213274Srpaulo         adjustment it made to the addend.  However, we set the addend
599213274Srpaulo         to 0 at the start of this function.  We need to adjust here,
600213274Srpaulo         to avoid the adjustment the generic code will make.  FIXME:
601213274Srpaulo         This is getting a bit hackish.  */
602213274Srpaulo      if (sym != NULL && sym->n_scnum != 0)
603213274Srpaulo	*addendp -= sym->n_value;
604213274Srpaulo    }
605213274Srpaulo
606213274Srpaulo  if (rel->r_type == R_AMD64_IMAGEBASE
607213274Srpaulo      && (bfd_get_flavour (sec->output_section->owner) == bfd_target_coff_flavour))
608213274Srpaulo    *addendp -= pe_data (sec->output_section->owner)->pe_opthdr.ImageBase;
609213274Srpaulo
610213274Srpaulo  if (rel->r_type == R_AMD64_SECREL)
611213274Srpaulo    {
612213274Srpaulo      bfd_vma osect_vma;
613213274Srpaulo
614213274Srpaulo      if (h && (h->type == bfd_link_hash_defined || h->type == bfd_link_hash_defweak))
615213274Srpaulo	osect_vma = h->root.u.def.section->output_section->vma;
616213274Srpaulo      else
617213274Srpaulo	{
618213274Srpaulo	  asection *sec;
619213274Srpaulo	  int i;
620213274Srpaulo
621213274Srpaulo	  /* Sigh, the only way to get the section to offset against
622213274Srpaulo	     is to find it the hard way.  */
623213274Srpaulo	  for (sec = abfd->sections, i = 1; i < sym->n_scnum; i++)
624213274Srpaulo	    sec = sec->next;
625213274Srpaulo
626213274Srpaulo	  osect_vma = sec->output_section->vma;
627213274Srpaulo	}
628213274Srpaulo
629213274Srpaulo      *addendp -= osect_vma;
630213274Srpaulo    }
631213274Srpaulo#endif
632213274Srpaulo
633213274Srpaulo  return howto;
634213274Srpaulo}
635213274Srpaulo
636213274Srpaulo#define coff_bfd_reloc_type_lookup coff_amd64_reloc_type_lookup
637218822Sdim#ifdef notyet
638213274Srpaulo#define coff_bfd_reloc_name_lookup coff_amd64_reloc_name_lookup
639218822Sdim#endif
640213274Srpaulo
641213274Srpaulostatic reloc_howto_type *
642213274Srpaulocoff_amd64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code)
643213274Srpaulo{
644213274Srpaulo  switch (code)
645213274Srpaulo    {
646213274Srpaulo    case BFD_RELOC_RVA:
647213274Srpaulo      return howto_table + R_AMD64_IMAGEBASE;
648213274Srpaulo    case BFD_RELOC_32:
649213274Srpaulo      return howto_table + R_AMD64_DIR32;
650213274Srpaulo    case BFD_RELOC_64:
651213274Srpaulo      return howto_table + R_AMD64_DIR64;
652213274Srpaulo    case BFD_RELOC_64_PCREL:
653213274Srpaulo#ifndef DONT_EXTEND_AMD64
654213274Srpaulo      return howto_table + R_AMD64_PCRQUAD;
655213274Srpaulo#else
656213274Srpaulo      /* Fall through.  */
657213274Srpaulo#endif
658213274Srpaulo    case BFD_RELOC_32_PCREL:
659213274Srpaulo      return howto_table + R_AMD64_PCRLONG;
660213274Srpaulo    case BFD_RELOC_X86_64_32S:
661213274Srpaulo      return howto_table + R_RELLONG;
662213274Srpaulo    case BFD_RELOC_16:
663213274Srpaulo      return howto_table + R_RELWORD;
664213274Srpaulo    case BFD_RELOC_16_PCREL:
665213274Srpaulo      return howto_table + R_PCRWORD;
666213274Srpaulo    case BFD_RELOC_8:
667213274Srpaulo      return howto_table + R_RELBYTE;
668213274Srpaulo    case BFD_RELOC_8_PCREL:
669213274Srpaulo      return howto_table + R_PCRBYTE;
670213274Srpaulo#ifdef notyet
671213274Srpaulo#if defined(COFF_WITH_PE)
672213274Srpaulo    case BFD_RELOC_32_SECREL:
673213274Srpaulo      return howto_table + R_AMD64_SECREL;
674213274Srpaulo#endif
675213274Srpaulo#endif
676213274Srpaulo    default:
677213274Srpaulo      BFD_FAIL ();
678213274Srpaulo      return 0;
679213274Srpaulo    }
680213274Srpaulo}
681213274Srpaulo
682218822Sdim#ifdef notyet
683213274Srpaulostatic reloc_howto_type *
684213274Srpaulocoff_amd64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
685213274Srpaulo			      const char *r_name)
686213274Srpaulo{
687213274Srpaulo  unsigned int i;
688213274Srpaulo
689213274Srpaulo  for (i = 0; i < sizeof (howto_table) / sizeof (howto_table[0]); i++)
690213274Srpaulo    if (howto_table[i].name != NULL
691213274Srpaulo	&& strcasecmp (howto_table[i].name, r_name) == 0)
692213274Srpaulo      return &howto_table[i];
693213274Srpaulo
694213274Srpaulo  return NULL;
695213274Srpaulo}
696218822Sdim#endif
697213274Srpaulo
698213274Srpaulo#define coff_rtype_to_howto coff_amd64_rtype_to_howto
699213274Srpaulo
700213274Srpaulo#ifdef TARGET_UNDERSCORE
701213274Srpaulo
702213274Srpaulo/* If amd64 gcc uses underscores for symbol names, then it does not use
703213274Srpaulo   a leading dot for local labels, so if TARGET_UNDERSCORE is defined
704213274Srpaulo   we treat all symbols starting with L as local.  */
705213274Srpaulo
706213274Srpaulostatic bfd_boolean
707213274Srpaulocoff_amd64_is_local_label_name (bfd *abfd, const char *name)
708213274Srpaulo{
709213274Srpaulo  if (name[0] == 'L')
710213274Srpaulo    return TRUE;
711213274Srpaulo
712213274Srpaulo  return _bfd_coff_is_local_label_name (abfd, name);
713213274Srpaulo}
714213274Srpaulo
715213274Srpaulo#define coff_bfd_is_local_label_name coff_amd64_is_local_label_name
716213274Srpaulo
717213274Srpaulo#endif /* TARGET_UNDERSCORE */
718213274Srpaulo
719213274Srpaulo#include "coffcode.h"
720213274Srpaulo
721213274Srpaulo#ifdef PE
722213274Srpaulo#define amd64coff_object_p pe_bfd_object_p
723213274Srpaulo#else
724213274Srpaulo#define amd64coff_object_p coff_object_p
725213274Srpaulo#endif
726213274Srpaulo
727213274Srpauloconst bfd_target
728213274Srpaulo#ifdef TARGET_SYM
729213274Srpaulo  TARGET_SYM =
730213274Srpaulo#else
731213274Srpaulo  x86_64coff_vec =
732213274Srpaulo#endif
733213274Srpaulo{
734213274Srpaulo#ifdef TARGET_NAME
735213274Srpaulo  TARGET_NAME,
736213274Srpaulo#else
737213274Srpaulo "coff-x86-64",			/* Name.  */
738213274Srpaulo#endif
739213274Srpaulo  bfd_target_coff_flavour,
740213274Srpaulo  BFD_ENDIAN_LITTLE,		/* Data byte order is little.  */
741213274Srpaulo  BFD_ENDIAN_LITTLE,		/* Header byte order is little.  */
742213274Srpaulo
743213274Srpaulo  (HAS_RELOC | EXEC_P |		/* Object flags.  */
744213274Srpaulo   HAS_LINENO | HAS_DEBUG |
745213274Srpaulo   HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
746213274Srpaulo
747213274Srpaulo  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* Section flags.  */
748213274Srpaulo#if defined(COFF_WITH_PE)
749213274Srpaulo   | SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_READONLY
750213274Srpaulo#endif
751213274Srpaulo   | SEC_CODE | SEC_DATA),
752213274Srpaulo
753213274Srpaulo#ifdef TARGET_UNDERSCORE
754213274Srpaulo  TARGET_UNDERSCORE,		/* Leading underscore.  */
755213274Srpaulo#else
756213274Srpaulo  0,				/* Leading underscore.  */
757213274Srpaulo#endif
758213274Srpaulo  '/',				/* Ar_pad_char.  */
759213274Srpaulo  15,				/* Ar_max_namelen.  */
760213274Srpaulo
761213274Srpaulo  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
762213274Srpaulo     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
763213274Srpaulo     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Data.  */
764213274Srpaulo  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
765213274Srpaulo     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
766213274Srpaulo     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Hdrs.  */
767213274Srpaulo
768213274Srpaulo  /* Note that we allow an object file to be treated as a core file as well.  */
769213274Srpaulo  { _bfd_dummy_target, amd64coff_object_p, /* BFD_check_format.  */
770213274Srpaulo    bfd_generic_archive_p, amd64coff_object_p },
771213274Srpaulo  { bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format.  */
772213274Srpaulo    bfd_false },
773213274Srpaulo  { bfd_false, coff_write_object_contents, /* bfd_write_contents.  */
774213274Srpaulo   _bfd_write_archive_contents, bfd_false },
775213274Srpaulo
776213274Srpaulo  BFD_JUMP_TABLE_GENERIC (coff),
777213274Srpaulo  BFD_JUMP_TABLE_COPY (coff),
778213274Srpaulo  BFD_JUMP_TABLE_CORE (_bfd_nocore),
779213274Srpaulo  BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
780213274Srpaulo  BFD_JUMP_TABLE_SYMBOLS (coff),
781213274Srpaulo  BFD_JUMP_TABLE_RELOCS (coff),
782213274Srpaulo  BFD_JUMP_TABLE_WRITE (coff),
783213274Srpaulo  BFD_JUMP_TABLE_LINK (coff),
784213274Srpaulo  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
785213274Srpaulo
786213274Srpaulo  NULL,
787213274Srpaulo
788213274Srpaulo  COFF_SWAP_TABLE
789213274Srpaulo};
790