1/* BFD back-end for AArch64 COFF files.
2   Copyright (C) 2021-2022 Free Software Foundation, Inc.
3
4   This file is part of BFD, the Binary File Descriptor library.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19   MA 02110-1301, USA.  */
20
21
22#ifndef COFF_WITH_peAArch64
23#define COFF_WITH_peAArch64
24#endif
25
26/* Note we have to make sure not to include headers twice.
27   Not all headers are wrapped in #ifdef guards, so we define
28   PEI_HEADERS to prevent double including here.  */
29#ifndef PEI_HEADERS
30#include "sysdep.h"
31#include "bfd.h"
32#include "libbfd.h"
33#include "coff/aarch64.h"
34#include "coff/internal.h"
35#include "coff/pe.h"
36#include "libcoff.h"
37#include "libiberty.h"
38#endif
39
40#include "libcoff.h"
41
42/* In case we're on a 32-bit machine, construct a 64-bit "-1" value.  */
43#define MINUS_ONE (~ (bfd_vma) 0)
44
45static const reloc_howto_type arm64_reloc_howto_64 = HOWTO(IMAGE_REL_ARM64_ADDR64, 0, 8, 64, false, 0,
46	 complain_overflow_bitfield,
47	 NULL, "64",
48	 false, MINUS_ONE, MINUS_ONE, false);
49
50static const reloc_howto_type arm64_reloc_howto_32 = HOWTO (IMAGE_REL_ARM64_ADDR32, 0, 4, 32, false, 0,
51	 complain_overflow_bitfield,
52	 NULL, "32",
53	 false, 0xffffffff, 0xffffffff, false);
54
55static const reloc_howto_type arm64_reloc_howto_32_pcrel = HOWTO (IMAGE_REL_ARM64_REL32, 0, 4, 32, true, 0,
56	 complain_overflow_bitfield,
57	 NULL, "DISP32",
58	 false, 0xffffffff, 0xffffffff, true);
59
60static const reloc_howto_type arm64_reloc_howto_branch26 = HOWTO (IMAGE_REL_ARM64_BRANCH26, 0, 4, 26, true, 0,
61	 complain_overflow_bitfield,
62	 NULL, "BRANCH26",
63	 false, 0x03ffffff, 0x03ffffff, true);
64
65static const reloc_howto_type arm64_reloc_howto_page21 = HOWTO (IMAGE_REL_ARM64_PAGEBASE_REL21, 12, 4, 21, true, 0,
66	 complain_overflow_signed,
67	 NULL, "PAGE21",
68	 false, 0x1fffff, 0x1fffff, false);
69
70static const reloc_howto_type arm64_reloc_howto_lo21 = HOWTO (IMAGE_REL_ARM64_REL21, 0, 4, 21, true, 0,
71	 complain_overflow_signed,
72	 NULL, "LO21",
73	 false, 0x1fffff, 0x1fffff, true);
74
75static const reloc_howto_type arm64_reloc_howto_pgoff12 = HOWTO (IMAGE_REL_ARM64_PAGEOFFSET_12L, 1, 4, 12, true, 0,
76	 complain_overflow_signed,
77	 NULL, "PGOFF12",
78	 false, 0xffe, 0xffe, true);
79
80static const reloc_howto_type arm64_reloc_howto_branch19 = HOWTO (IMAGE_REL_ARM64_BRANCH19, 2, 4, 19, true, 0,
81	 complain_overflow_signed,
82	 NULL, "BRANCH19",
83	 false, 0x7ffff, 0x7ffff, true);
84
85
86static const reloc_howto_type* const arm64_howto_table[] = {
87     &arm64_reloc_howto_64,
88     &arm64_reloc_howto_32,
89     &arm64_reloc_howto_32_pcrel,
90     &arm64_reloc_howto_branch26,
91     &arm64_reloc_howto_page21,
92     &arm64_reloc_howto_lo21,
93     &arm64_reloc_howto_pgoff12,
94     &arm64_reloc_howto_branch19
95};
96
97#ifndef NUM_ELEM
98#define NUM_ELEM(a) ((sizeof (a)) / sizeof ((a)[0]))
99#endif
100
101#define NUM_RELOCS NUM_ELEM (arm64_howto_table)
102
103#define coff_bfd_reloc_type_lookup		coff_aarch64_reloc_type_lookup
104#define coff_bfd_reloc_name_lookup		coff_aarch64_reloc_name_lookup
105
106static reloc_howto_type *
107coff_aarch64_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code)
108{
109  switch (code)
110  {
111  case BFD_RELOC_64:
112    return &arm64_reloc_howto_64;
113  case BFD_RELOC_32:
114    return &arm64_reloc_howto_32;
115  case BFD_RELOC_32_PCREL:
116    return &arm64_reloc_howto_32_pcrel;
117  case BFD_RELOC_AARCH64_CALL26:
118  case BFD_RELOC_AARCH64_JUMP26:
119    return &arm64_reloc_howto_branch26;
120  case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
121    return &arm64_reloc_howto_page21;
122  case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
123    return &arm64_reloc_howto_lo21;
124  case BFD_RELOC_AARCH64_LDST16_LO12:
125    return &arm64_reloc_howto_pgoff12;
126  case BFD_RELOC_AARCH64_BRANCH19:
127    return &arm64_reloc_howto_branch19;
128  default:
129    BFD_FAIL ();
130    return NULL;
131  }
132
133  return NULL;
134}
135
136static reloc_howto_type *
137coff_aarch64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
138			    const char *r_name)
139{
140	unsigned int i;
141
142	for (i = 0; i < NUM_RELOCS; i++)
143	  if (arm64_howto_table[i]->name != NULL
144	    && strcasecmp (arm64_howto_table[i]->name, r_name) == 0)
145	    return arm64_howto_table[i];
146
147  return NULL;
148}
149
150#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER  2
151#define COFF_PAGE_SIZE			      0x1000
152
153static reloc_howto_type *
154coff_aarch64_rtype_lookup (unsigned int code)
155{
156  switch (code)
157  {
158    case IMAGE_REL_ARM64_ADDR64:
159      return &arm64_reloc_howto_64;
160    case IMAGE_REL_ARM64_ADDR32:
161      return &arm64_reloc_howto_32;
162    case IMAGE_REL_ARM64_REL32:
163      return &arm64_reloc_howto_32_pcrel;
164    case IMAGE_REL_ARM64_BRANCH26:
165      return &arm64_reloc_howto_branch26;
166    case IMAGE_REL_ARM64_PAGEBASE_REL21:
167      return &arm64_reloc_howto_page21;
168    case IMAGE_REL_ARM64_REL21:
169      return &arm64_reloc_howto_lo21;
170    case IMAGE_REL_ARM64_PAGEOFFSET_12L:
171      return &arm64_reloc_howto_pgoff12;
172    case IMAGE_REL_ARM64_BRANCH19:
173      return &arm64_reloc_howto_branch19;
174    default:
175      BFD_FAIL ();
176      return NULL;
177  }
178
179  return NULL;
180}
181
182#define RTYPE2HOWTO(cache_ptr, dst)				\
183  ((cache_ptr)->howto =	coff_aarch64_rtype_lookup((dst)->r_type))
184
185#define SELECT_RELOC(x,howto) { (x).r_type = (howto)->type; }
186
187#ifndef bfd_pe_print_pdata
188#define bfd_pe_print_pdata      NULL
189#endif
190
191/* Handle include/coff/aarch64.h external_reloc.  */
192#define SWAP_IN_RELOC_OFFSET	H_GET_32
193#define SWAP_OUT_RELOC_OFFSET	H_PUT_32
194
195/* Return TRUE if this relocation should
196   appear in the output .reloc section.  */
197
198static bool
199in_reloc_p (bfd * abfd ATTRIBUTE_UNUSED,
200            reloc_howto_type * howto)
201{
202  return !howto->pc_relative;
203}
204
205#include "coffcode.h"
206
207/* Target vectors.  */
208const bfd_target
209#ifdef TARGET_SYM
210  TARGET_SYM =
211#else
212# error "target symbol name not specified"
213#endif
214{
215#ifdef TARGET_NAME
216  TARGET_NAME,
217#else
218# error "target name not specified"
219#endif
220  bfd_target_coff_flavour,
221  BFD_ENDIAN_LITTLE,		/* Data byte order is little.  */
222  BFD_ENDIAN_LITTLE,		/* Header byte order is little.  */
223
224  (HAS_RELOC | EXEC_P		/* Object flags.  */
225   | HAS_LINENO | HAS_DEBUG
226   | HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS),
227
228  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* Section flags.  */
229#if defined(COFF_WITH_PE)
230   | SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_READONLY | SEC_DEBUGGING
231#endif
232   | SEC_CODE | SEC_DATA | SEC_EXCLUDE ),
233
234#ifdef TARGET_UNDERSCORE
235  TARGET_UNDERSCORE,		/* Leading underscore.  */
236#else
237  0,				/* Leading underscore.  */
238#endif
239  '/',				/* Ar_pad_char.  */
240  15,				/* Ar_max_namelen.  */
241  0,				/* match priority.  */
242  TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols.  */
243
244  /* Data conversion functions.  */
245  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
246  bfd_getl32, bfd_getl_signed_32, bfd_putl32,
247  bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Data.  */
248  /* Header conversion functions.  */
249  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
250  bfd_getl32, bfd_getl_signed_32, bfd_putl32,
251  bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Hdrs.  */
252
253  /* Note that we allow an object file to be treated as a core file as well.  */
254  {				/* bfd_check_format.  */
255    _bfd_dummy_target,
256    coff_object_p,
257    bfd_generic_archive_p,
258    coff_object_p
259  },
260  {				/* bfd_set_format.  */
261    _bfd_bool_bfd_false_error,
262    coff_mkobject,
263    _bfd_generic_mkarchive,
264    _bfd_bool_bfd_false_error
265  },
266  {				/* bfd_write_contents.  */
267    _bfd_bool_bfd_false_error,
268    coff_write_object_contents,
269    _bfd_write_archive_contents,
270    _bfd_bool_bfd_false_error
271  },
272
273  BFD_JUMP_TABLE_GENERIC (coff),
274  BFD_JUMP_TABLE_COPY (coff),
275  BFD_JUMP_TABLE_CORE (_bfd_nocore),
276  BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
277  BFD_JUMP_TABLE_SYMBOLS (coff),
278  BFD_JUMP_TABLE_RELOCS (coff),
279  BFD_JUMP_TABLE_WRITE (coff),
280  BFD_JUMP_TABLE_LINK (coff),
281  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
282
283  NULL,
284
285  COFF_SWAP_TABLE
286};
287