Initial s390x relocation support (#515)
[pyelftools.git] / elftools / elf / relocation.py
1 #-------------------------------------------------------------------------------
2 # elftools: elf/relocation.py
3 #
4 # ELF relocations
5 #
6 # Eli Bendersky (eliben@gmail.com)
7 # This code is in the public domain
8 #-------------------------------------------------------------------------------
9 from collections import namedtuple
10
11 from ..common.exceptions import ELFRelocationError
12 from ..common.utils import elf_assert, struct_parse
13 from .sections import Section
14 from .enums import (
15 ENUM_RELOC_TYPE_i386, ENUM_RELOC_TYPE_x64, ENUM_RELOC_TYPE_MIPS,
16 ENUM_RELOC_TYPE_ARM, ENUM_RELOC_TYPE_AARCH64, ENUM_RELOC_TYPE_PPC64,
17 ENUM_RELOC_TYPE_S390X, ENUM_RELOC_TYPE_BPF, ENUM_RELOC_TYPE_LOONGARCH,
18 ENUM_D_TAG)
19 from ..construct import Container
20
21
22 class Relocation(object):
23 """ Relocation object - representing a single relocation entry. Allows
24 dictionary-like access to the entry's fields.
25
26 Can be either a REL or RELA relocation.
27 """
28 def __init__(self, entry, elffile):
29 self.entry = entry
30 self.elffile = elffile
31
32 def is_RELA(self):
33 """ Is this a RELA relocation? If not, it's REL.
34 """
35 return 'r_addend' in self.entry
36
37 def __getitem__(self, name):
38 """ Dict-like access to entries
39 """
40 return self.entry[name]
41
42 def __repr__(self):
43 return '<Relocation (%s): %s>' % (
44 'RELA' if self.is_RELA() else 'REL',
45 self.entry)
46
47 def __str__(self):
48 return self.__repr__()
49
50
51 class RelocationTable(object):
52 """ Shared functionality between relocation sections and relocation tables
53 """
54
55 def __init__(self, elffile, offset, size, is_rela):
56 self._stream = elffile.stream
57 self._elffile = elffile
58 self._elfstructs = elffile.structs
59 self._size = size
60 self._offset = offset
61 self._is_rela = is_rela
62
63 if is_rela:
64 self.entry_struct = self._elfstructs.Elf_Rela
65 else:
66 self.entry_struct = self._elfstructs.Elf_Rel
67
68 self.entry_size = self.entry_struct.sizeof()
69
70 def is_RELA(self):
71 """ Is this a RELA relocation section? If not, it's REL.
72 """
73 return self._is_rela
74
75 def num_relocations(self):
76 """ Number of relocations in the section
77 """
78 return self._size // self.entry_size
79
80 def get_relocation(self, n):
81 """ Get the relocation at index #n from the section (Relocation object)
82 """
83 entry_offset = self._offset + n * self.entry_size
84 entry = struct_parse(
85 self.entry_struct,
86 self._stream,
87 stream_pos=entry_offset)
88 return Relocation(entry, self._elffile)
89
90 def iter_relocations(self):
91 """ Yield all the relocations in the section
92 """
93 for i in range(self.num_relocations()):
94 yield self.get_relocation(i)
95
96
97 class RelocationSection(Section, RelocationTable):
98 """ ELF relocation section. Serves as a collection of Relocation entries.
99 """
100 def __init__(self, header, name, elffile):
101 Section.__init__(self, header, name, elffile)
102 RelocationTable.__init__(self, self.elffile,
103 self['sh_offset'], self['sh_size'], header['sh_type'] == 'SHT_RELA')
104
105 elf_assert(header['sh_type'] in ('SHT_REL', 'SHT_RELA'),
106 'Unknown relocation type section')
107 elf_assert(header['sh_entsize'] == self.entry_size,
108 'Expected sh_entsize of %s section to be %s' % (
109 header['sh_type'], self.entry_size))
110
111
112 class RelrRelocationTable(object):
113 """ RELR compressed relocation table. This stores relative relocations
114 in a compressed format. An entry with an even value serves as an
115 'anchor' that defines a base address. Following this entry are one or
116 more bitmaps for consecutive addresses after the anchor which determine
117 if the corresponding relocation exists (if the bit is 1) or if it is
118 skipped. Addends are stored at the respective addresses (as in REL
119 relocations).
120 """
121
122 def __init__(self, elffile, offset, size, entrysize):
123 self._elffile = elffile
124 self._offset = offset
125 self._size = size
126 self._relr_struct = self._elffile.structs.Elf_Relr
127 self._entrysize = self._relr_struct.sizeof()
128 self._cached_relocations = None
129
130 elf_assert(self._entrysize == entrysize,
131 'Expected RELR entry size to be %s, got %s' % (
132 self._entrysize, entrysize))
133
134 def iter_relocations(self):
135 """ Yield all the relocations in the section
136 """
137
138 # If DT_RELRSZ is zero, offset is meaningless and could be None.
139 if self._size == 0:
140 return []
141
142 limit = self._offset + self._size
143 relr = self._offset
144 # The addresses of relocations in a bitmap are calculated from a base
145 # value provided in an initial 'anchor' relocation.
146 base = None
147 while relr < limit:
148 entry = struct_parse(self._relr_struct,
149 self._elffile.stream,
150 stream_pos=relr)
151 entry_offset = entry['r_offset']
152 if (entry_offset & 1) == 0:
153 # We found an anchor, take the current value as the base address
154 # for the following bitmaps and move the 'where' pointer to the
155 # beginning of the first bitmap.
156 base = entry_offset
157 base += self._entrysize
158 yield Relocation(entry, self._elffile)
159 else:
160 # We're processing a bitmap.
161 elf_assert(base is not None, 'RELR bitmap without base address')
162 i = 0
163 while True:
164 # Iterate over all bits except the least significant one.
165 entry_offset = (entry_offset >> 1)
166 if entry_offset == 0:
167 break
168 # if the current LSB is set, we have a relocation at the
169 # corresponding address so generate a Relocation with the
170 # matching offset
171 if (entry_offset & 1) != 0:
172 calc_offset = base + i * self._entrysize
173 yield Relocation(Container(r_offset = calc_offset),
174 self._elffile)
175 i += 1
176 # Advance 'base' past the current bitmap (8 == CHAR_BIT). There
177 # are 63 (or 31 for 32-bit ELFs) entries in each bitmap, and
178 # every bit corresponds to an ELF_addr-sized relocation.
179 base += (8 * self._entrysize - 1) * self._elffile.structs.Elf_addr('').sizeof()
180 # Advance to the next entry
181 relr += self._entrysize
182
183 def num_relocations(self):
184 """ Number of relocations in the section
185 """
186 if self._cached_relocations is None:
187 self._cached_relocations = list(self.iter_relocations())
188 return len(self._cached_relocations)
189
190 def get_relocation(self, n):
191 """ Get the relocation at index #n from the section (Relocation object)
192 """
193 if self._cached_relocations is None:
194 self._cached_relocations = list(self.iter_relocations())
195 return self._cached_relocations[n]
196
197
198 class RelrRelocationSection(Section, RelrRelocationTable):
199 """ ELF RELR relocation section. Serves as a collection of RELR relocation entries.
200 """
201 def __init__(self, header, name, elffile):
202 Section.__init__(self, header, name, elffile)
203 RelrRelocationTable.__init__(self, self.elffile,
204 self['sh_offset'], self['sh_size'], self['sh_entsize'])
205
206
207 class RelocationHandler(object):
208 """ Handles the logic of relocations in ELF files.
209 """
210 def __init__(self, elffile):
211 self.elffile = elffile
212
213 def find_relocations_for_section(self, section):
214 """ Given a section, find the relocation section for it in the ELF
215 file. Return a RelocationSection object, or None if none was
216 found.
217 """
218 reloc_section_names = (
219 '.rel' + section.name,
220 '.rela' + section.name)
221 # Find the relocation section aimed at this one. Currently assume
222 # that either .rel or .rela section exists for this section, but
223 # not both.
224 for relsection in self.elffile.iter_sections():
225 if ( isinstance(relsection, RelocationSection) and
226 relsection.name in reloc_section_names):
227 return relsection
228 return None
229
230 def apply_section_relocations(self, stream, reloc_section):
231 """ Apply all relocations in reloc_section (a RelocationSection object)
232 to the given stream, that contains the data of the section that is
233 being relocated. The stream is modified as a result.
234 """
235 # The symbol table associated with this relocation section
236 symtab = self.elffile.get_section(reloc_section['sh_link'])
237 for reloc in reloc_section.iter_relocations():
238 self._do_apply_relocation(stream, reloc, symtab)
239
240 def _do_apply_relocation(self, stream, reloc, symtab):
241 # Preparations for performing the relocation: obtain the value of
242 # the symbol mentioned in the relocation, as well as the relocation
243 # recipe which tells us how to actually perform it.
244 # All peppered with some sanity checking.
245 if reloc['r_info_sym'] >= symtab.num_symbols():
246 raise ELFRelocationError(
247 'Invalid symbol reference in relocation: index %s' % (
248 reloc['r_info_sym']))
249 sym_value = symtab.get_symbol(reloc['r_info_sym'])['st_value']
250
251 reloc_type = reloc['r_info_type']
252 recipe = None
253
254 if self.elffile.get_machine_arch() == 'x86':
255 if reloc.is_RELA():
256 raise ELFRelocationError(
257 'Unexpected RELA relocation for x86: %s' % reloc)
258 recipe = self._RELOCATION_RECIPES_X86.get(reloc_type, None)
259 elif self.elffile.get_machine_arch() == 'x64':
260 if not reloc.is_RELA():
261 raise ELFRelocationError(
262 'Unexpected REL relocation for x64: %s' % reloc)
263 recipe = self._RELOCATION_RECIPES_X64.get(reloc_type, None)
264 elif self.elffile.get_machine_arch() == 'MIPS':
265 if reloc.is_RELA():
266 if reloc_type == ENUM_RELOC_TYPE_MIPS['R_MIPS_64']:
267 if reloc['r_type2'] != 0 or reloc['r_type3'] != 0 or reloc['r_ssym'] != 0:
268 raise ELFRelocationError(
269 'Multiple relocations in R_MIPS_64 are not implemented: %s' % reloc)
270 recipe = self._RELOCATION_RECIPES_MIPS_RELA.get(reloc_type, None)
271 else:
272 recipe = self._RELOCATION_RECIPES_MIPS_REL.get(reloc_type, None)
273 elif self.elffile.get_machine_arch() == 'ARM':
274 if reloc.is_RELA():
275 raise ELFRelocationError(
276 'Unexpected RELA relocation for ARM: %s' % reloc)
277 recipe = self._RELOCATION_RECIPES_ARM.get(reloc_type, None)
278 elif self.elffile.get_machine_arch() == 'AArch64':
279 recipe = self._RELOCATION_RECIPES_AARCH64.get(reloc_type, None)
280 elif self.elffile.get_machine_arch() == '64-bit PowerPC':
281 recipe = self._RELOCATION_RECIPES_PPC64.get(reloc_type, None)
282 elif self.elffile.get_machine_arch() == 'IBM S/390':
283 recipe = self._RELOCATION_RECIPES_S390X.get(reloc_type, None)
284 elif self.elffile.get_machine_arch() == 'Linux BPF - in-kernel virtual machine':
285 recipe = self._RELOCATION_RECIPES_EBPF.get(reloc_type, None)
286 elif self.elffile.get_machine_arch() == 'LoongArch':
287 if not reloc.is_RELA():
288 raise ELFRelocationError(
289 'Unexpected REL relocation for LoongArch: %s' % reloc)
290 recipe = self._RELOCATION_RECIPES_LOONGARCH.get(reloc_type, None)
291
292 if recipe is None:
293 raise ELFRelocationError(
294 'Unsupported relocation type: %s' % reloc_type)
295
296 # So now we have everything we need to actually perform the relocation.
297 # Let's get to it:
298
299 # 0. Find out which struct we're going to be using to read this value
300 # from the stream and write it back.
301 if recipe.bytesize == 4:
302 value_struct = self.elffile.structs.Elf_word('')
303 elif recipe.bytesize == 8:
304 value_struct = self.elffile.structs.Elf_word64('')
305 elif recipe.bytesize == 1:
306 value_struct = self.elffile.structs.Elf_byte('')
307 elif recipe.bytesize == 2:
308 value_struct = self.elffile.structs.Elf_half('')
309 else:
310 raise ELFRelocationError('Invalid bytesize %s for relocation' %
311 recipe.bytesize)
312
313 # 1. Read the value from the stream (with correct size and endianness)
314 original_value = struct_parse(
315 value_struct,
316 stream,
317 stream_pos=reloc['r_offset'])
318 # 2. Apply the relocation to the value, acting according to the recipe
319 relocated_value = recipe.calc_func(
320 value=original_value,
321 sym_value=sym_value,
322 offset=reloc['r_offset'],
323 addend=reloc['r_addend'] if recipe.has_addend else 0)
324 # 3. Write the relocated value back into the stream
325 stream.seek(reloc['r_offset'])
326
327 # Make sure the relocated value fits back by wrapping it around. This
328 # looks like a problem, but it seems to be the way this is done in
329 # binutils too.
330 relocated_value = relocated_value % (2 ** (recipe.bytesize * 8))
331 value_struct.build_stream(relocated_value, stream)
332
333 # Relocations are represented by "recipes". Each recipe specifies:
334 # bytesize: The number of bytes to read (and write back) to the section.
335 # This is the unit of data on which relocation is performed.
336 # has_addend: Does this relocation have an extra addend?
337 # calc_func: A function that performs the relocation on an extracted
338 # value, and returns the updated value.
339 #
340 _RELOCATION_RECIPE_TYPE = namedtuple('_RELOCATION_RECIPE_TYPE',
341 'bytesize has_addend calc_func')
342
343 def _reloc_calc_identity(value, sym_value, offset, addend=0):
344 return value
345
346 def _reloc_calc_sym_plus_value(value, sym_value, offset, addend=0):
347 return sym_value + value + addend
348
349 def _reloc_calc_sym_plus_value_pcrel(value, sym_value, offset, addend=0):
350 return sym_value + value - offset
351
352 def _reloc_calc_sym_plus_addend(value, sym_value, offset, addend=0):
353 return sym_value + addend
354
355 def _reloc_calc_sym_plus_addend_pcrel(value, sym_value, offset, addend=0):
356 return sym_value + addend - offset
357
358 def _reloc_calc_value_minus_sym_addend(value, sym_value, offset, addend=0):
359 return value - sym_value - addend
360
361 def _arm_reloc_calc_sym_plus_value_pcrel(value, sym_value, offset, addend=0):
362 return sym_value // 4 + value - offset // 4
363
364 def _bpf_64_32_reloc_calc_sym_plus_addend(value, sym_value, offset, addend=0):
365 return (sym_value + addend) // 8 - 1
366
367 _RELOCATION_RECIPES_ARM = {
368 ENUM_RELOC_TYPE_ARM['R_ARM_ABS32']: _RELOCATION_RECIPE_TYPE(
369 bytesize=4, has_addend=False,
370 calc_func=_reloc_calc_sym_plus_value),
371 ENUM_RELOC_TYPE_ARM['R_ARM_CALL']: _RELOCATION_RECIPE_TYPE(
372 bytesize=4, has_addend=False,
373 calc_func=_arm_reloc_calc_sym_plus_value_pcrel),
374 }
375
376 _RELOCATION_RECIPES_AARCH64 = {
377 ENUM_RELOC_TYPE_AARCH64['R_AARCH64_ABS64']: _RELOCATION_RECIPE_TYPE(
378 bytesize=8, has_addend=True, calc_func=_reloc_calc_sym_plus_addend),
379 ENUM_RELOC_TYPE_AARCH64['R_AARCH64_ABS32']: _RELOCATION_RECIPE_TYPE(
380 bytesize=4, has_addend=True, calc_func=_reloc_calc_sym_plus_addend),
381 ENUM_RELOC_TYPE_AARCH64['R_AARCH64_PREL32']: _RELOCATION_RECIPE_TYPE(
382 bytesize=4, has_addend=True,
383 calc_func=_reloc_calc_sym_plus_addend_pcrel),
384 }
385
386 # https://dmz-portal.mips.com/wiki/MIPS_relocation_types
387 _RELOCATION_RECIPES_MIPS_REL = {
388 ENUM_RELOC_TYPE_MIPS['R_MIPS_NONE']: _RELOCATION_RECIPE_TYPE(
389 bytesize=4, has_addend=False, calc_func=_reloc_calc_identity),
390 ENUM_RELOC_TYPE_MIPS['R_MIPS_32']: _RELOCATION_RECIPE_TYPE(
391 bytesize=4, has_addend=False,
392 calc_func=_reloc_calc_sym_plus_value),
393 }
394 _RELOCATION_RECIPES_MIPS_RELA = {
395 ENUM_RELOC_TYPE_MIPS['R_MIPS_NONE']: _RELOCATION_RECIPE_TYPE(
396 bytesize=4, has_addend=True, calc_func=_reloc_calc_identity),
397 ENUM_RELOC_TYPE_MIPS['R_MIPS_32']: _RELOCATION_RECIPE_TYPE(
398 bytesize=4, has_addend=True,
399 calc_func=_reloc_calc_sym_plus_value),
400 ENUM_RELOC_TYPE_MIPS['R_MIPS_64']: _RELOCATION_RECIPE_TYPE(
401 bytesize=8, has_addend=True,
402 calc_func=_reloc_calc_sym_plus_value),
403 }
404
405 _RELOCATION_RECIPES_PPC64 = {
406 ENUM_RELOC_TYPE_PPC64['R_PPC64_ADDR32']: _RELOCATION_RECIPE_TYPE(
407 bytesize=4, has_addend=True, calc_func=_reloc_calc_sym_plus_addend),
408 ENUM_RELOC_TYPE_PPC64['R_PPC64_REL32']: _RELOCATION_RECIPE_TYPE(
409 bytesize=4, has_addend=True, calc_func=_reloc_calc_sym_plus_addend_pcrel),
410 ENUM_RELOC_TYPE_PPC64['R_PPC64_ADDR64']: _RELOCATION_RECIPE_TYPE(
411 bytesize=8, has_addend=True, calc_func=_reloc_calc_sym_plus_addend),
412 }
413
414 _RELOCATION_RECIPES_X86 = {
415 ENUM_RELOC_TYPE_i386['R_386_NONE']: _RELOCATION_RECIPE_TYPE(
416 bytesize=4, has_addend=False, calc_func=_reloc_calc_identity),
417 ENUM_RELOC_TYPE_i386['R_386_32']: _RELOCATION_RECIPE_TYPE(
418 bytesize=4, has_addend=False,
419 calc_func=_reloc_calc_sym_plus_value),
420 ENUM_RELOC_TYPE_i386['R_386_PC32']: _RELOCATION_RECIPE_TYPE(
421 bytesize=4, has_addend=False,
422 calc_func=_reloc_calc_sym_plus_value_pcrel),
423 }
424
425 _RELOCATION_RECIPES_X64 = {
426 ENUM_RELOC_TYPE_x64['R_X86_64_NONE']: _RELOCATION_RECIPE_TYPE(
427 bytesize=8, has_addend=True, calc_func=_reloc_calc_identity),
428 ENUM_RELOC_TYPE_x64['R_X86_64_64']: _RELOCATION_RECIPE_TYPE(
429 bytesize=8, has_addend=True, calc_func=_reloc_calc_sym_plus_addend),
430 ENUM_RELOC_TYPE_x64['R_X86_64_PC32']: _RELOCATION_RECIPE_TYPE(
431 bytesize=4, has_addend=True,
432 calc_func=_reloc_calc_sym_plus_addend_pcrel),
433 ENUM_RELOC_TYPE_x64['R_X86_64_32']: _RELOCATION_RECIPE_TYPE(
434 bytesize=4, has_addend=True, calc_func=_reloc_calc_sym_plus_addend),
435 ENUM_RELOC_TYPE_x64['R_X86_64_32S']: _RELOCATION_RECIPE_TYPE(
436 bytesize=4, has_addend=True, calc_func=_reloc_calc_sym_plus_addend),
437 }
438
439 # https://www.kernel.org/doc/html/latest/bpf/llvm_reloc.html#different-relocation-types
440 _RELOCATION_RECIPES_EBPF = {
441 ENUM_RELOC_TYPE_BPF['R_BPF_NONE']: _RELOCATION_RECIPE_TYPE(
442 bytesize=8, has_addend=False, calc_func=_reloc_calc_identity),
443 ENUM_RELOC_TYPE_BPF['R_BPF_64_64']: _RELOCATION_RECIPE_TYPE(
444 bytesize=8, has_addend=False, calc_func=_reloc_calc_identity),
445 ENUM_RELOC_TYPE_BPF['R_BPF_64_32']: _RELOCATION_RECIPE_TYPE(
446 bytesize=8, has_addend=False, calc_func=_bpf_64_32_reloc_calc_sym_plus_addend),
447 ENUM_RELOC_TYPE_BPF['R_BPF_64_NODYLD32']: _RELOCATION_RECIPE_TYPE(
448 bytesize=4, has_addend=False, calc_func=_reloc_calc_identity),
449 ENUM_RELOC_TYPE_BPF['R_BPF_64_ABS64']: _RELOCATION_RECIPE_TYPE(
450 bytesize=8, has_addend=False, calc_func=_reloc_calc_identity),
451 ENUM_RELOC_TYPE_BPF['R_BPF_64_ABS32']: _RELOCATION_RECIPE_TYPE(
452 bytesize=4, has_addend=False, calc_func=_reloc_calc_identity),
453 }
454
455 # https://github.com/loongson/la-abi-specs/blob/release/laelf.adoc
456 _RELOCATION_RECIPES_LOONGARCH = {
457 ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_NONE']: _RELOCATION_RECIPE_TYPE(
458 bytesize=4, has_addend=False, calc_func=_reloc_calc_identity),
459 ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_32']: _RELOCATION_RECIPE_TYPE(
460 bytesize=4, has_addend=True,
461 calc_func=_reloc_calc_sym_plus_addend),
462 ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_64']: _RELOCATION_RECIPE_TYPE(
463 bytesize=8, has_addend=True,
464 calc_func=_reloc_calc_sym_plus_addend),
465 ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_ADD8']: _RELOCATION_RECIPE_TYPE(
466 bytesize=1, has_addend=True,
467 calc_func=_reloc_calc_sym_plus_value),
468 ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_SUB8']: _RELOCATION_RECIPE_TYPE(
469 bytesize=1, has_addend=True,
470 calc_func=_reloc_calc_value_minus_sym_addend),
471 ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_ADD16']: _RELOCATION_RECIPE_TYPE(
472 bytesize=2, has_addend=True,
473 calc_func=_reloc_calc_sym_plus_value),
474 ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_SUB16']: _RELOCATION_RECIPE_TYPE(
475 bytesize=2, has_addend=True,
476 calc_func=_reloc_calc_value_minus_sym_addend),
477 ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_ADD32']: _RELOCATION_RECIPE_TYPE(
478 bytesize=4, has_addend=True,
479 calc_func=_reloc_calc_sym_plus_value),
480 ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_SUB32']: _RELOCATION_RECIPE_TYPE(
481 bytesize=4, has_addend=True,
482 calc_func=_reloc_calc_value_minus_sym_addend),
483 ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_ADD64']: _RELOCATION_RECIPE_TYPE(
484 bytesize=8, has_addend=True,
485 calc_func=_reloc_calc_sym_plus_value),
486 ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_SUB64']: _RELOCATION_RECIPE_TYPE(
487 bytesize=8, has_addend=True,
488 calc_func=_reloc_calc_value_minus_sym_addend),
489 ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_32_PCREL']: _RELOCATION_RECIPE_TYPE(
490 bytesize=4, has_addend=True,
491 calc_func=_reloc_calc_sym_plus_addend_pcrel),
492 ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_64_PCREL']: _RELOCATION_RECIPE_TYPE(
493 bytesize=8, has_addend=True,
494 calc_func=_reloc_calc_sym_plus_addend_pcrel),
495 }
496
497 _RELOCATION_RECIPES_S390X = {
498 ENUM_RELOC_TYPE_S390X['R_390_32']: _RELOCATION_RECIPE_TYPE(
499 bytesize=4, has_addend=True, calc_func=_reloc_calc_sym_plus_addend),
500 ENUM_RELOC_TYPE_S390X['R_390_PC32']: _RELOCATION_RECIPE_TYPE(
501 bytesize=4, has_addend=True, calc_func=_reloc_calc_sym_plus_addend_pcrel),
502 ENUM_RELOC_TYPE_S390X['R_390_64']: _RELOCATION_RECIPE_TYPE(
503 bytesize=8, has_addend=True, calc_func=_reloc_calc_sym_plus_addend),
504 }
505
506