btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / system / kernel / arch / x86 / arch_elf.cpp
blob204eb522ac28b16507334f2052ee549553caeb03
1 /*
2 * Copyright 2004-2008, Haiku Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT license.
5 * Copyright 2002, Travis Geiselbrecht. All rights reserved.
6 * Distributed under the terms of the NewOS License.
7 */
10 #ifdef _BOOT_MODE
11 # include <boot/arch.h>
12 #endif
14 #include <KernelExport.h>
16 #include <elf_priv.h>
17 #include <arch/elf.h>
20 //#define TRACE_ARCH_ELF
21 #ifdef TRACE_ARCH_ELF
22 # define TRACE(x) dprintf x
23 #else
24 # define TRACE(x) ;
25 #endif
28 #ifndef _BOOT_MODE
29 static bool
30 is_in_image(struct elf_image_info *image, addr_t address)
32 return (address >= image->text_region.start
33 && address < image->text_region.start + image->text_region.size)
34 || (address >= image->data_region.start
35 && address < image->data_region.start + image->data_region.size);
37 #endif // !_BOOT_MODE
40 #if !defined(__x86_64__) || (defined(_BOOT_MODE) && _BOOT_PLATFORM != efi)
43 #ifdef TRACE_ARCH_ELF
44 static const char *kRelocations[] = {
45 "R_386_NONE",
46 "R_386_32", /* add symbol value */
47 "R_386_PC32", /* add PC relative symbol value */
48 "R_386_GOT32", /* add PC relative GOT offset */
49 "R_386_PLT32", /* add PC relative PLT offset */
50 "R_386_COPY", /* copy data from shared object */
51 "R_386_GLOB_DAT", /* set GOT entry to data address */
52 "R_386_JMP_SLOT", /* set GOT entry to code address */
53 "R_386_RELATIVE", /* add load address of shared object */
54 "R_386_GOTOFF", /* add GOT relative symbol address */
55 "R_386_GOTPC", /* add PC relative GOT table address */
57 #endif
60 #ifdef _BOOT_MODE
61 status_t
62 boot_arch_elf_relocate_rel(struct preloaded_elf32_image *image, Elf32_Rel *rel,
63 int relLength)
64 #else
65 int
66 arch_elf_relocate_rel(struct elf_image_info *image,
67 struct elf_image_info *resolveImage, Elf32_Rel *rel, int relLength)
68 #endif
70 addr_t S;
71 addr_t A;
72 addr_t P;
73 addr_t finalAddress;
74 addr_t *resolveAddress;
75 int i;
77 S = A = P = 0;
79 for (i = 0; i * (int)sizeof(Elf32_Rel) < relLength; i++) {
80 TRACE(("looking at rel type %s, offset 0x%lx\n",
81 kRelocations[ELF32_R_TYPE(rel[i].r_info)], rel[i].r_offset));
83 // calc S
84 switch (ELF32_R_TYPE(rel[i].r_info)) {
85 case R_386_32:
86 case R_386_PC32:
87 case R_386_GLOB_DAT:
88 case R_386_JMP_SLOT:
89 case R_386_GOTOFF:
91 Elf32_Sym *symbol;
92 status_t status;
94 symbol = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));
96 #ifdef _BOOT_MODE
97 status = boot_elf_resolve_symbol(image, symbol, &S);
98 #else
99 status = elf_resolve_symbol(image, symbol, resolveImage, &S);
100 #endif
101 if (status < B_OK)
102 return status;
103 TRACE(("S %p (%s)\n", (void *)S, SYMNAME(image, symbol)));
106 // calc A
107 switch (ELF32_R_TYPE(rel[i].r_info)) {
108 case R_386_32:
109 case R_386_PC32:
110 case R_386_GOT32:
111 case R_386_PLT32:
112 case R_386_RELATIVE:
113 case R_386_GOTOFF:
114 case R_386_GOTPC:
115 A = *(addr_t *)(image->text_region.delta + rel[i].r_offset);
116 TRACE(("A %p\n", (void *)A));
117 break;
119 // calc P
120 switch (ELF32_R_TYPE(rel[i].r_info)) {
121 case R_386_PC32:
122 case R_386_GOT32:
123 case R_386_PLT32:
124 case R_386_GOTPC:
125 P = image->text_region.delta + rel[i].r_offset;
126 TRACE(("P %p\n", (void *)P));
127 break;
130 switch (ELF32_R_TYPE(rel[i].r_info)) {
131 case R_386_NONE:
132 continue;
133 case R_386_32:
134 finalAddress = S + A;
135 break;
136 case R_386_PC32:
137 finalAddress = S + A - P;
138 break;
139 case R_386_RELATIVE:
140 // B + A;
141 finalAddress = image->text_region.delta + A;
142 break;
143 case R_386_JMP_SLOT:
144 case R_386_GLOB_DAT:
145 finalAddress = S;
146 break;
148 default:
149 dprintf("arch_elf_relocate_rel: unhandled relocation type %d\n",
150 ELF32_R_TYPE(rel[i].r_info));
151 return B_BAD_DATA;
154 resolveAddress = (addr_t *)(image->text_region.delta + rel[i].r_offset);
155 #ifndef _BOOT_MODE
156 if (!is_in_image(image, (addr_t)resolveAddress)) {
157 dprintf("arch_elf_relocate_rel: invalid offset %#lx\n",
158 rel[i].r_offset);
159 return B_BAD_ADDRESS;
161 #endif
162 *resolveAddress = finalAddress;
163 TRACE(("-> offset %#lx = %#lx\n",
164 (image->text_region.delta + rel[i].r_offset), finalAddress));
167 return B_NO_ERROR;
171 #ifdef _BOOT_MODE
172 status_t
173 boot_arch_elf_relocate_rela(struct preloaded_elf32_image *image,
174 Elf32_Rela *rel, int relLength)
175 #else
177 arch_elf_relocate_rela(struct elf_image_info *image,
178 struct elf_image_info *resolveImage, Elf32_Rela *rel, int relLength)
179 #endif
181 dprintf("arch_elf_relocate_rela: not supported on x86\n");
182 return B_ERROR;
186 #endif // !__x86_64__ || (_BOOT_MODE && _BOOT_PLATFORM != efi)
189 #if defined(__x86_64__) || defined(_BOOT_MODE)
192 #ifdef _BOOT_MODE
193 status_t
194 boot_arch_elf_relocate_rel(preloaded_elf64_image* image, Elf64_Rel* rel,
195 int relLength)
196 #else
198 arch_elf_relocate_rel(struct elf_image_info *image,
199 struct elf_image_info *resolveImage, Elf64_Rel *rel, int relLength)
200 #endif
202 dprintf("arch_elf_relocate_rel: not supported on x86_64\n");
203 return B_ERROR;
207 #ifdef _BOOT_MODE
208 status_t
209 boot_arch_elf_relocate_rela(preloaded_elf64_image* image, Elf64_Rela* rel,
210 int relLength)
211 #else
213 arch_elf_relocate_rela(struct elf_image_info *image,
214 struct elf_image_info *resolveImage, Elf64_Rela *rel, int relLength)
215 #endif
217 for (int i = 0; i < relLength / (int)sizeof(Elf64_Rela); i++) {
218 int type = ELF64_R_TYPE(rel[i].r_info);
219 int symIndex = ELF64_R_SYM(rel[i].r_info);
220 Elf64_Addr symAddr = 0;
222 // Resolve the symbol, if any.
223 if (symIndex != 0) {
224 Elf64_Sym* symbol = SYMBOL(image, symIndex);
226 status_t status;
227 #ifdef _BOOT_MODE
228 status = boot_elf_resolve_symbol(image, symbol, &symAddr);
229 #else
230 status = elf_resolve_symbol(image, symbol, resolveImage, &symAddr);
231 #endif
232 if (status < B_OK)
233 return status;
236 // Address of the relocation.
237 Elf64_Addr relocAddr = image->text_region.delta + rel[i].r_offset;
239 // Calculate the relocation value.
240 Elf64_Addr relocValue;
241 switch(type) {
242 case R_X86_64_NONE:
243 continue;
244 case R_X86_64_64:
245 relocValue = symAddr + rel[i].r_addend;
246 break;
247 case R_X86_64_PC32:
248 relocValue = symAddr + rel[i].r_addend - rel[i].r_offset;
249 break;
250 case R_X86_64_GLOB_DAT:
251 case R_X86_64_JUMP_SLOT:
252 relocValue = symAddr + rel[i].r_addend;
253 break;
254 case R_X86_64_RELATIVE:
255 relocValue = image->text_region.delta + rel[i].r_addend;
256 break;
257 default:
258 dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n",
259 type);
260 return B_BAD_DATA;
262 #ifdef _BOOT_MODE
263 boot_elf64_set_relocation(relocAddr, relocValue);
264 #else
265 if (!is_in_image(image, relocAddr)) {
266 dprintf("arch_elf_relocate_rela: invalid offset %#lx\n",
267 rel[i].r_offset);
268 return B_BAD_ADDRESS;
271 *(Elf64_Addr *)relocAddr = relocValue;
272 #endif
275 return B_OK;
279 #endif // __x86_64__ || _BOOT_MODE