1/*
  2 * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
  3 *
  4 * @APPLE_LICENSE_HEADER_START@
  5 * 
  6 * This file contains Original Code and/or Modifications of Original Code
  7 * as defined in and that are subject to the Apple Public Source License
  8 * Version 2.0 (the 'License'). You may not use this file except in
  9 * compliance with the License. Please obtain a copy of the License at
 10 * http://www.opensource.apple.com/apsl/ and read it before using this
 11 * file.
 12 * 
 13 * The Original Code and all software distributed under the License are
 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 18 * Please see the License for the specific language governing rights and
 19 * limitations under the License.
 20 * 
 21 * @APPLE_LICENSE_HEADER_END@
 22 */
 23
 24#ifndef _MACHO_ARM64_RELOC_H_
 25#define _MACHO_ARM64_RELOC_H_
 26
 27/*
 28 * Relocations for arm64 are a bit different than for other architectures in
 29 * Mach-O: Scattered relocations are not used.  Almost all relocations produced
 30 * by the compiler are external relocations.  An external relocation has the
 31 * r_extern bit set to 1 and the r_symbolnum field contains the symbol table
 32 * index of the target label.
 33 *
 34 * When the assembler is generating relocations, if the target label is a local
 35 * label (begins with 'L'), then the previous non-local label in the same
 36 * section is used as the target of the external relocation.  An addend is used
 37 * with the distance from that non-local label to the target label.  Only when
 38 * there is no previous non-local label in the section is an internal
 39 * relocation used.
 40 *
 41 * The addend (i.e. the 4 in _foo+4) is encoded either in the instruction or
 42 * in the r_symbolnum of ARM64_RELOC_ADDEND.
 43 * For ARM64_RELOC_UNSIGNED and ARM64_RELOC_AUTHENTICATED_POINTER, the addend
 44 * is stored in the instruction.  ARM64_RELOC_PAGE21, ARM64_RELOC_PAGEOFF12 and
 45 * ARM64_RELOC_BRANCH26 must be preceded by an ARM64_RELOC_ADDEND if they need
 46 * an addend.  No other relocations support addends.
 47 *
 48 * The relocation types are:
 49 *
 50 *     ARM64_RELOC_UNSIGNED                 // For pointer sized fixups
 51 *     ARM64_RELOC_SUBTRACTOR               // must be followed by a ARM64_RELOC_UNSIGNED
 52 *     ARM64_RELOC_BRANCH26                 // a BL instruction with pc-relative +-128MB displacement
 53 *     ARM64_RELOC_PAGE21                   // pc-rel distance to page of target
 54 *     ARM64_RELOC_PAGEOFF12                // offset within page, scaled by r_length
 55 *     ARM64_RELOC_GOT_LOAD_PAGE21          // load with a pc-rel distance to page of a GOT entry
 56 *     ARM64_RELOC_GOT_LOAD_PAGEOFF12       // load with an offset within page, scaled by r_length, of GOT entry
 57 *     ARM64_RELOC_POINTER_TO_GOT           // 32-bit pc-rel (or 64-bit absolute) offset to a GOT entry
 58 *     ARM64_RELOC_TLVP_LOAD_PAGE21         // tlv load with a pc-rel distance to page of a GOT entry
 59 *     ARM64_RELOC_TLVP_LOAD_PAGEOFF12      // tlv load with an offset within page, scaled by r_length, of GOT entry
 60 *     ARM64_RELOC_ADDEND                   // must be followed by ARM64_RELOC_BRANCH26/ARM64_RELOC_PAGE21/ARM64_RELOC_PAGEOFF12
 61 *     ARM64_RELOC_AUTHENTICATED_POINTER    // 64-bit pointer with authentication
 62 *
 63 * The following are sample assembly instructions, followed by the relocation
 64 * and section content they generate in an object file:
 65 *
 66 *     (arm64_32 only)
 67 *     .long _foo
 68 *         r_type=ARM64_RELOC_UNSIGNED, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_foo
 69 *         00 00 00 00
 70 *
 71 *     (arm64_32 only)
 72 *     .long _foo + 4
 73 *         r_type=ARM64_RELOC_UNSIGNED, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_foo
 74 *         04 00 00 00
 75 *
 76 *     .quad _foo
 77 *         r_type=ARM64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
 78 *         00 00 00 00 00 00 00 00
 79 *
 80 *     .quad _foo + 16
 81 *         r_type=ARM64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
 82 *         10 00 00 00 00 00 00 00
 83 *
 84 *     .quad L1
 85 *         r_type=ARM64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_prev
 86 *         10 00 00 00 00 00 00 00
 87 *         // assumes _prev is the first non-local label 0x10 bytes before L1
 88 *         10 00 00 00 00 00 00 00
 89 *
 90 *     (arm64_32 only)
 91 *     .long _foo - _bar
 92 *         r_type=ARM64_RELOC_SUBTRACTOR, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_bar
 93 *         r_type=ARM64_RELOC_UNSIGNED, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_foo
 94 *         00 00 00 00
 95 *
 96 *     (arm64_32 only)
 97 *     .long _foo - _bar + 4
 98 *         r_type=ARM64_RELOC_SUBTRACTOR, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_bar
 99 *         r_type=ARM64_RELOC_UNSIGNED, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_foo
100 *         04 00 00 00
101 *
102 *     .quad _foo - _bar
103 *         r_type=ARM64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_bar
104 *         r_type=ARM64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
105 *         00 00 00 00 00 00 00 00
106 *
107 *     .quad _foo - _bar + 4
108 *         r_type=ARM64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_bar
109 *         r_type=ARM64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
110 *         04 00 00 00 00 00 00 00
111 *
112 *     .long _foo - .
113 *         r_type=ARM64_RELOC_SUBTRACTOR, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_prev
114 *         r_type=ARM64_RELOC_UNSIGNED, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_foo
115 *         f8 ff ff ff
116 *         // assumes _prev is the first non-local label 0x8 bytes before this
117 *         // .quad
118 *
119 *     .long _foo - L1
120 *         r_type=ARM64_RELOC_SUBTRACTOR, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_prev
121 *         r_type=ARM64_RELOC_UNSIGNED, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_foo
122 *         f8 ff ff ff
123 *         // assumes _prev is the first non-local label 0x8 bytes before L1
124 *
125 *     .quad _foo - .
126 *         r_type=ARM64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_prev
127 *         r_type=ARM64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
128 *         f8 ff ff ff ff ff ff ff
129 *         // assumes _prev is the first non-local label 0x8 bytes before this
130 *         // .quad
131 *
132 *     .quad _foo - L1
133 *         r_type=ARM64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_prev
134 *         r_type=ARM64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
135 *         f8 ff ff ff ff ff ff ff
136 *         // assumes _prev is the first non-local label 0x8 bytes before L1
137 *
138 *     .long L1 - _prev
139 *         // No relocations.  This is an assembly time constant.
140 *         12 00 00 00 00 00 00 00
141 *         // assumes _prev is the first non-local label 0x12 bytes before L1
142 *
143 *     .quad L1 - _prev
144 *         // No relocations.  This is an assembly time constant.
145 *         12 00 00 00 00 00 00 00
146 *         // assumes _prev is the first non-local label 0x12 bytes before L1
147 *
148 *     bl _foo
149 *         r_type=ARM64_RELOC_BRANCH26, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
150 *         0x14000000
151 *
152 *     bl _foo + 4
153 *         r_type=ARM64_RELOC_ADDEND, r_length=2, r_extern=0, r_pcrel=0, r_symbolnum=0x000004
154 *         r_type=ARM64_RELOC_BRANCH26, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
155 *         0x14000000
156 *
157 *     adrp x0, _foo@PAGE
158 *         r_type=ARM64_RELOC_PAGE21, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
159 *         0x90000000
160 *
161 *     ldr x0, [x0, _foo@PAGEOFF]
162 *         r_type=ARM64_RELOC_PAGEOFF12, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_foo
163 *         0xf9400000
164 *
165 *     adrp x0, _foo@PAGE + 0x24
166 *         r_type=ARM64_RELOC_ADDEND, r_length=2, r_extern=0, r_pcrel=0, r_symbolnum=0x000024
167 *         r_type=ARM64_RELOC_PAGE21, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
168 *         0x90000000
169 *
170 *     ldr x0, [x0, _foo@PAGEOFF + 0x24]
171 *         r_type=ARM64_RELOC_ADDEND, r_length=2, r_extern=0, r_pcrel=0, r_symbolnum=0x000024
172 *         r_type=ARM64_RELOC_PAGEOFF12, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_foo
173 *         0xf9400000
174 *
175 *     adrp x0, _foo@GOTPAGE
176 *         r_type=ARM64_RELOC_GOT_LOAD_PAGE21, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
177 *         0x90000000
178 *
179 *     ldr x0, [x0, _foo@GOTPAGEOFF]
180 *         r_type=ARM64_RELOC_GOT_LOAD_PAGEOFF12, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_foo
181 *         0xf9400000
182 *
183 *     adrp x0, _foo@TLVPPAGE
184 *         r_type=ARM64_RELOC_TLVP_LOAD_PAGE21, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
185 *         0x90000000
186 *
187 *     ldr x0, [x0, _foo@TLVPPAGEOFF]
188 *         r_type=ARM64_RELOC_TLVP_LOAD_PAGEOFF12, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_foo
189 *         0xf9400000
190 *
191 *     .long _foo@GOT - .
192 *         r_type=ARM64_RELOC_POINTER_TO_GOT, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
193 *         00 00 00 00
194 *
195 *     (arm64_32 only)
196 *     .long _foo@GOT
197 *         r_type=ARM64_RELOC_POINTER_TO_GOT, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_foo
198 *         00 00 00 00
199 *
200 *     .quad _foo@GOT
201 *         r_type=ARM64_RELOC_POINTER_TO_GOT, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
202 *         00 00 00 00 00 00 00 00
203 *
204 *     (arm64e only)
205 *     .quad _foo@AUTH(da,5,addr)
206 *         r_type=ARM64_RELOC_AUTHENTICATED_POINTER, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
207 *         00 00 00 00 05 00 05 80
208 *
209 *     (arm64e only)
210 *     .quad (_foo + 0x10)@AUTH(da,5,addr)
211 *         r_type=ARM64_RELOC_AUTHENTICATED_POINTER, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
212 *         10 00 00 00 05 00 05 80
213 *
214 *
215 */
216enum reloc_type_arm64
217{
218    ARM64_RELOC_UNSIGNED,	  // for pointers
219    ARM64_RELOC_SUBTRACTOR,       // must be followed by a ARM64_RELOC_UNSIGNED
220    ARM64_RELOC_BRANCH26,         // a B/BL instruction with 26-bit displacement
221    ARM64_RELOC_PAGE21,           // pc-rel distance to page of target
222    ARM64_RELOC_PAGEOFF12,        // offset within page, scaled by r_length
223    ARM64_RELOC_GOT_LOAD_PAGE21,  // pc-rel distance to page of GOT slot
224    ARM64_RELOC_GOT_LOAD_PAGEOFF12, // offset within page of GOT slot,
225                                    //  scaled by r_length
226    ARM64_RELOC_POINTER_TO_GOT,   // for pointers to GOT slots
227    ARM64_RELOC_TLVP_LOAD_PAGE21, // pc-rel distance to page of TLVP slot
228    ARM64_RELOC_TLVP_LOAD_PAGEOFF12, // offset within page of TLVP slot,
229                                     //  scaled by r_length
230    ARM64_RELOC_ADDEND,		  // must be followed by PAGE21 or PAGEOFF12
231
232    // An arm64e authenticated pointer.
233    //
234    // Represents a pointer to a symbol (like ARM64_RELOC_UNSIGNED).
235    // Additionally, the resulting pointer is signed.  The signature is
236    // specified in the target location: the addend is restricted to the lower
237    // 32 bits (instead of the full 64 bits for ARM64_RELOC_UNSIGNED):
238    //
239    //   |63|62|61-51|50-49|  48  |47     -     32|31  -  0|
240    //   | 1| 0|  0  | key | addr | discriminator | addend |
241    //
242    // The key is one of:
243    //   IA: 00 IB: 01
244    //   DA: 10 DB: 11
245    //
246    // The discriminator field is used as extra signature diversification.
247    //
248    // The addr field indicates whether the target address should be blended
249    // into the discriminator.
250    //
251    ARM64_RELOC_AUTHENTICATED_POINTER,
252};
253
254#endif /* #ifndef _MACHO_ARM64_RELOC_H_ */