1/* Intel x86-64 Mach-O support for BFD.
2   Copyright 2010
3   Free Software Foundation, Inc.
4
5   This file is part of BFD, the Binary File Descriptor library.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20   MA 02110-1301, USA.  */
21
22#include "sysdep.h"
23#include "mach-o.h"
24#include "bfd.h"
25#include "libbfd.h"
26#include "libiberty.h"
27
28#define bfd_mach_o_object_p bfd_mach_o_x86_64_object_p
29#define bfd_mach_o_core_p bfd_mach_o_x86_64_core_p
30#define bfd_mach_o_mkobject bfd_mach_o_x86_64_mkobject
31
32static const bfd_target *
33bfd_mach_o_x86_64_object_p (bfd *abfd)
34{
35  return bfd_mach_o_header_p (abfd, 0, BFD_MACH_O_CPU_TYPE_X86_64);
36}
37
38static const bfd_target *
39bfd_mach_o_x86_64_core_p (bfd *abfd)
40{
41  return bfd_mach_o_header_p (abfd,
42                              BFD_MACH_O_MH_CORE, BFD_MACH_O_CPU_TYPE_X86_64);
43}
44
45static bfd_boolean
46bfd_mach_o_x86_64_mkobject (bfd *abfd)
47{
48  bfd_mach_o_data_struct *mdata;
49
50  if (!bfd_mach_o_mkobject_init (abfd))
51    return FALSE;
52
53  mdata = bfd_mach_o_get_data (abfd);
54  mdata->header.magic = BFD_MACH_O_MH_MAGIC;
55  mdata->header.cputype = BFD_MACH_O_CPU_TYPE_X86_64;
56  mdata->header.cpusubtype = BFD_MACH_O_CPU_SUBTYPE_X86_ALL;
57  mdata->header.byteorder = BFD_ENDIAN_LITTLE;
58  mdata->header.version = 1;
59
60  return TRUE;
61}
62
63/* In case we're on a 32-bit machine, construct a 64-bit "-1" value.  */
64#define MINUS_ONE (~ (bfd_vma) 0)
65
66static reloc_howto_type x86_64_howto_table[]=
67{
68  /* 0 */
69  HOWTO(BFD_RELOC_64, 0, 4, 64, FALSE, 0,
70	complain_overflow_bitfield,
71	NULL, "64",
72	FALSE, MINUS_ONE, MINUS_ONE, FALSE),
73  HOWTO(BFD_RELOC_32, 0, 2, 32, FALSE, 0,
74	complain_overflow_bitfield,
75	NULL, "32",
76	FALSE, 0xffffffff, 0xffffffff, FALSE),
77  HOWTO(BFD_RELOC_32_PCREL, 0, 2, 32, TRUE, 0,
78	complain_overflow_bitfield,
79	NULL, "DISP32",
80	FALSE, 0xffffffff, 0xffffffff, TRUE),
81  HOWTO(BFD_RELOC_MACH_O_X86_64_PCREL32_1, 0, 2, 32, TRUE, 0,
82	complain_overflow_bitfield,
83	NULL, "DISP32_1",
84	FALSE, 0xffffffff, 0xffffffff, TRUE),
85  /* 4 */
86  HOWTO(BFD_RELOC_MACH_O_X86_64_PCREL32_2, 0, 2, 32, TRUE, 0,
87	complain_overflow_bitfield,
88	NULL, "DISP32_2",
89	FALSE, 0xffffffff, 0xffffffff, TRUE),
90  HOWTO(BFD_RELOC_MACH_O_X86_64_PCREL32_4, 0, 2, 32, TRUE, 0,
91	complain_overflow_bitfield,
92	NULL, "DISP32_4",
93	FALSE, 0xffffffff, 0xffffffff, TRUE),
94  HOWTO(BFD_RELOC_MACH_O_X86_64_BRANCH32, 0, 2, 32, TRUE, 0,
95	complain_overflow_bitfield,
96	NULL, "BRANCH32",
97	FALSE, 0xffffffff, 0xffffffff, TRUE),
98  HOWTO(BFD_RELOC_MACH_O_X86_64_GOT_LOAD, 0, 2, 32, TRUE, 0,
99	complain_overflow_bitfield,
100	NULL, "GOT_LOAD",
101	FALSE, 0xffffffff, 0xffffffff, TRUE),
102  /* 8 */
103  HOWTO(BFD_RELOC_MACH_O_X86_64_SUBTRACTOR32, 0, 2, 32, FALSE, 0,
104	complain_overflow_bitfield,
105	NULL, "SUBTRACTOR32",
106	FALSE, 0xffffffff, 0xffffffff, FALSE),
107  HOWTO(BFD_RELOC_MACH_O_X86_64_SUBTRACTOR64, 0, 4, 64, FALSE, 0,
108	complain_overflow_bitfield,
109	NULL, "SUBTRACTOR64",
110	FALSE, MINUS_ONE, MINUS_ONE, FALSE),
111  HOWTO(BFD_RELOC_MACH_O_X86_64_GOT, 0, 2, 32, TRUE, 0,
112	complain_overflow_bitfield,
113	NULL, "GOT",
114	FALSE, 0xffffffff, 0xffffffff, TRUE),
115  HOWTO(BFD_RELOC_MACH_O_X86_64_BRANCH8, 0, 0, 8, TRUE, 0,
116	complain_overflow_bitfield,
117	NULL, "BRANCH8",
118	FALSE, 0xff, 0xff, TRUE),
119};
120
121static bfd_boolean
122bfd_mach_o_x86_64_swap_reloc_in (arelent *res, bfd_mach_o_reloc_info *reloc)
123{
124  /* On x86-64, scattered relocs are not used.  */
125  if (reloc->r_scattered)
126    return FALSE;
127
128  switch (reloc->r_type)
129    {
130    case BFD_MACH_O_X86_64_RELOC_UNSIGNED:
131      if (reloc->r_pcrel)
132        return FALSE;
133      switch (reloc->r_length)
134        {
135        case 2:
136          res->howto = &x86_64_howto_table[1];
137          return TRUE;
138        case 3:
139          res->howto = &x86_64_howto_table[0];
140          return TRUE;
141        default:
142          return FALSE;
143        }
144    case BFD_MACH_O_X86_64_RELOC_SIGNED:
145      if (reloc->r_length == 2 && reloc->r_pcrel)
146        {
147          res->howto = &x86_64_howto_table[2];
148          return TRUE;
149        }
150      break;
151    case BFD_MACH_O_X86_64_RELOC_BRANCH:
152      if (!reloc->r_pcrel)
153        return FALSE;
154      switch (reloc->r_length)
155        {
156        case 2:
157          res->howto = &x86_64_howto_table[6];
158          return TRUE;
159        default:
160          return FALSE;
161        }
162      break;
163    case BFD_MACH_O_X86_64_RELOC_GOT_LOAD:
164      if (reloc->r_length == 2 && reloc->r_pcrel && reloc->r_extern)
165        {
166          res->howto = &x86_64_howto_table[7];
167          return TRUE;
168        }
169      break;
170    case BFD_MACH_O_X86_64_RELOC_GOT:
171      if (reloc->r_length == 2 && reloc->r_pcrel && reloc->r_extern)
172        {
173          res->howto = &x86_64_howto_table[10];
174          return TRUE;
175        }
176      break;
177    case BFD_MACH_O_X86_64_RELOC_SUBTRACTOR:
178      if (reloc->r_pcrel)
179        return FALSE;
180      switch (reloc->r_length)
181        {
182        case 2:
183          res->howto = &x86_64_howto_table[8];
184          return TRUE;
185        case 3:
186          res->howto = &x86_64_howto_table[9];
187          return TRUE;
188        default:
189          return FALSE;
190        }
191      break;
192    case BFD_MACH_O_X86_64_RELOC_SIGNED_1:
193      if (reloc->r_length == 2 && reloc->r_pcrel)
194        {
195          res->howto = &x86_64_howto_table[3];
196          return TRUE;
197        }
198      break;
199    case BFD_MACH_O_X86_64_RELOC_SIGNED_2:
200      if (reloc->r_length == 2 && reloc->r_pcrel)
201        {
202          res->howto = &x86_64_howto_table[4];
203          return TRUE;
204        }
205      break;
206    case BFD_MACH_O_X86_64_RELOC_SIGNED_4:
207      if (reloc->r_length == 2 && reloc->r_pcrel)
208        {
209          res->howto = &x86_64_howto_table[5];
210          return TRUE;
211        }
212      break;
213    default:
214      return FALSE;
215    }
216  return FALSE;
217}
218
219static bfd_boolean
220bfd_mach_o_x86_64_swap_reloc_out (arelent *rel, bfd_mach_o_reloc_info *rinfo)
221{
222  rinfo->r_address = rel->address;
223  switch (rel->howto->type)
224    {
225    case BFD_RELOC_64:
226      rinfo->r_scattered = 0;
227      rinfo->r_type = BFD_MACH_O_X86_64_RELOC_UNSIGNED;
228      rinfo->r_pcrel = 0;
229      rinfo->r_length = rel->howto->size; /* Correct in practice.  */
230      if ((*rel->sym_ptr_ptr)->flags & BSF_SECTION_SYM)
231        {
232          rinfo->r_extern = 0;
233          rinfo->r_value = (*rel->sym_ptr_ptr)->section->target_index;
234        }
235      else
236        {
237          rinfo->r_extern = 1;
238          rinfo->r_value = (*rel->sym_ptr_ptr)->udata.i;
239        }
240      break;
241    default:
242      return FALSE;
243    }
244  return TRUE;
245}
246
247static reloc_howto_type *
248bfd_mach_o_x86_64_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
249                                         bfd_reloc_code_real_type code)
250{
251  unsigned int i;
252
253  for (i = 0;
254       i < sizeof (x86_64_howto_table) / sizeof (*x86_64_howto_table);
255       i++)
256    if (code == x86_64_howto_table[i].type)
257      return &x86_64_howto_table[i];
258  return NULL;
259}
260
261static reloc_howto_type *
262bfd_mach_o_x86_64_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
263                                         const char *name ATTRIBUTE_UNUSED)
264{
265  return NULL;
266}
267
268#define bfd_mach_o_swap_reloc_in bfd_mach_o_x86_64_swap_reloc_in
269#define bfd_mach_o_swap_reloc_out bfd_mach_o_x86_64_swap_reloc_out
270
271#define bfd_mach_o_bfd_reloc_type_lookup bfd_mach_o_x86_64_bfd_reloc_type_lookup
272#define bfd_mach_o_bfd_reloc_name_lookup bfd_mach_o_x86_64_bfd_reloc_name_lookup
273#define bfd_mach_o_print_thread NULL
274
275#define TARGET_NAME 		mach_o_x86_64_vec
276#define TARGET_STRING 		"mach-o-x86-64"
277#define TARGET_ARCHITECTURE	bfd_arch_i386
278#define TARGET_BIG_ENDIAN 	0
279#define TARGET_ARCHIVE 		0
280#include "mach-o-target.c"
281