1/*
2 * Copyright 2004-2018 Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 * Copyright 2002, Travis Geiselbrecht. All rights reserved.
5 * Distributed under the terms of the NewOS License.
6 */
7
8
9#ifdef _BOOT_MODE
10#	include <boot/arch.h>
11#endif
12
13#include <KernelExport.h>
14
15#include <elf_priv.h>
16#include <arch/elf.h>
17
18
19//#define TRACE_ARCH_ELF
20#ifdef TRACE_ARCH_ELF
21#	define TRACE(x) dprintf x
22#else
23#	define TRACE(x) ;
24#endif
25
26
27#ifndef _BOOT_MODE
28static bool
29is_in_image(struct elf_image_info *image, addr_t address)
30{
31	return (address >= image->text_region.start
32			&& address < image->text_region.start + image->text_region.size)
33		|| (address >= image->data_region.start
34			&& address < image->data_region.start + image->data_region.size);
35}
36#endif	// !_BOOT_MODE
37
38
39#ifdef _BOOT_MODE
40status_t
41boot_arch_elf_relocate_rel(preloaded_elf64_image* image, Elf64_Rel* rel,
42	int relLength)
43#else
44int
45arch_elf_relocate_rel(struct elf_image_info *image,
46	struct elf_image_info *resolveImage, Elf64_Rel *rel, int relLength)
47#endif
48{
49	dprintf("arch_elf_relocate_rel: not supported on arm64\n");
50	return B_ERROR;
51}
52
53
54#ifdef _BOOT_MODE
55status_t
56boot_arch_elf_relocate_rela(preloaded_elf64_image* image, Elf64_Rela* rel,
57	int relLength)
58#else
59int
60arch_elf_relocate_rela(struct elf_image_info *image,
61	struct elf_image_info *resolveImage, Elf64_Rela *rel, int relLength)
62#endif
63{
64	for (int i = 0; i < relLength / (int)sizeof(Elf64_Rela); i++) {
65		int type = ELF64_R_TYPE(rel[i].r_info);
66		int symIndex = ELF64_R_SYM(rel[i].r_info);
67		Elf64_Addr symAddr = 0;
68
69		// Resolve the symbol, if any.
70		if (symIndex != 0) {
71			Elf64_Sym* symbol = SYMBOL(image, symIndex);
72
73			status_t status;
74#ifdef _BOOT_MODE
75			status = boot_elf_resolve_symbol(image, symbol, &symAddr);
76#else
77			status = elf_resolve_symbol(image, symbol, resolveImage, &symAddr);
78#endif
79			if (status < B_OK)
80				return status;
81		}
82
83		// Address of the relocation.
84		Elf64_Addr relocAddr = image->text_region.delta + rel[i].r_offset;
85
86		// Calculate the relocation value.
87		Elf64_Addr relocValue;
88		switch (type) {
89			case R_AARCH64_NONE:
90				continue;
91			case R_AARCH64_ABS64:
92				relocValue = symAddr + rel[i].r_addend;
93				break;
94			case R_AARCH64_ABS32:
95			case R_AARCH64_ABS16:
96			case R_AARCH64_PREL64:
97			case R_AARCH64_PREL32:
98			case R_AARCH64_PREL16:
99			case R_AARCH64_TSTBR14:
100			case R_AARCH64_CONDBR19:
101			case R_AARCH64_JUMP26:
102			case R_AARCH64_CALL26:
103			case R_AARCH64_COPY:
104				dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n",
105					type);
106				return B_BAD_DATA;
107			case R_AARCH64_GLOB_DAT:
108			case R_AARCH64_JUMP_SLOT:
109				relocValue = symAddr + rel[i].r_addend;
110				break;
111			case R_AARCH64_RELATIVE:
112				relocValue = image->text_region.delta + rel[i].r_addend;
113				break;
114			case R_AARCH64_TLS_DTPREL64:
115			case R_AARCH64_TLS_DTPMOD64:
116			case R_AARCH64_TLS_TPREL64:
117			case R_AARCH64_TLSDESC:
118			case R_AARCH64_IRELATIVE:
119			default:
120				dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n",
121					type);
122				return B_BAD_DATA;
123		}
124
125#ifdef _BOOT_MODE
126		boot_elf64_set_relocation(relocAddr, relocValue);
127#else
128		if (!is_in_image(image, relocAddr)) {
129			dprintf("arch_elf_relocate_rela: invalid offset %#lx\n",
130				rel[i].r_offset);
131			return B_BAD_ADDRESS;
132		}
133		*(Elf64_Addr *)relocAddr = relocValue;
134#endif
135	}
136
137	return B_OK;
138}
139