xref: /haiku/src/system/kernel/arch/x86/arch_elf.cpp (revision 922e7ba1f3228e6f28db69b0ded8f86eb32dea17)
1 /*
2  * Copyright 2004-2008, Haiku Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT license.
4  *
5  * Copyright 2002, Travis Geiselbrecht. All rights reserved.
6  * Distributed under the terms of the NewOS License.
7  */
8 
9 
10 #ifdef _BOOT_MODE
11 #	include <boot/arch.h>
12 #endif
13 
14 #include <KernelExport.h>
15 
16 #include <elf_priv.h>
17 #include <arch/elf.h>
18 
19 
20 //#define TRACE_ARCH_ELF
21 #ifdef TRACE_ARCH_ELF
22 #	define TRACE(x) dprintf x
23 #else
24 #	define TRACE(x) ;
25 #endif
26 
27 
28 #ifdef TRACE_ARCH_ELF
29 static const char *kRelocations[] = {
30 	"R_386_NONE",
31 	"R_386_32",			/* add symbol value */
32 	"R_386_PC32",		/* add PC relative symbol value */
33 	"R_386_GOT32",		/* add PC relative GOT offset */
34 	"R_386_PLT32",		/* add PC relative PLT offset */
35 	"R_386_COPY",		/* copy data from shared object */
36 	"R_386_GLOB_DAT",	/* set GOT entry to data address */
37 	"R_386_JMP_SLOT",	/* set GOT entry to code address */
38 	"R_386_RELATIVE",	/* add load address of shared object */
39 	"R_386_GOTOFF",		/* add GOT relative symbol address */
40 	"R_386_GOTPC",		/* add PC relative GOT table address */
41 };
42 #endif
43 
44 
45 #ifndef _BOOT_MODE
46 static bool
47 is_in_image(struct elf_image_info *image, addr_t address)
48 {
49 	return (address >= image->text_region.start
50 			&& address < image->text_region.start + image->text_region.size)
51 		|| (address >= image->data_region.start
52 			&& address < image->data_region.start + image->data_region.size);
53 }
54 #endif	// !_BOOT_MODE
55 
56 
57 #ifdef _BOOT_MODE
58 status_t
59 boot_arch_elf_relocate_rel(struct preloaded_image *image,
60 	struct Elf32_Rel *rel, int relLength)
61 #else
62 int
63 arch_elf_relocate_rel(struct elf_image_info *image,
64 	struct elf_image_info *resolveImage, struct Elf32_Rel *rel, int relLength)
65 #endif
66 {
67 	addr_t S;
68 	addr_t A;
69 	addr_t P;
70 	addr_t finalAddress;
71 	addr_t *resolveAddress;
72 	int i;
73 
74 	S = A = P = 0;
75 
76 	for (i = 0; i * (int)sizeof(struct Elf32_Rel) < relLength; i++) {
77 		TRACE(("looking at rel type %s, offset 0x%lx\n",
78 			kRelocations[ELF32_R_TYPE(rel[i].r_info)], rel[i].r_offset));
79 
80 		// calc S
81 		switch (ELF32_R_TYPE(rel[i].r_info)) {
82 			case R_386_32:
83 			case R_386_PC32:
84 			case R_386_GLOB_DAT:
85 			case R_386_JMP_SLOT:
86 			case R_386_GOTOFF:
87 			{
88 				struct Elf32_Sym *symbol;
89 				status_t status;
90 
91 				symbol = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));
92 
93 #ifdef _BOOT_MODE
94 				status = boot_elf_resolve_symbol(image, symbol, &S);
95 #else
96 				status = elf_resolve_symbol(image, symbol, resolveImage, &S);
97 #endif
98 				if (status < B_OK)
99 					return status;
100 				TRACE(("S %p (%s)\n", (void *)S, SYMNAME(image, symbol)));
101 			}
102 		}
103 		// calc A
104 		switch (ELF32_R_TYPE(rel[i].r_info)) {
105 			case R_386_32:
106 			case R_386_PC32:
107 			case R_386_GOT32:
108 			case R_386_PLT32:
109 			case R_386_RELATIVE:
110 			case R_386_GOTOFF:
111 			case R_386_GOTPC:
112 				A = *(addr_t *)(image->text_region.delta + rel[i].r_offset);
113 				TRACE(("A %p\n", (void *)A));
114 				break;
115 		}
116 		// calc P
117 		switch (ELF32_R_TYPE(rel[i].r_info)) {
118 			case R_386_PC32:
119 			case R_386_GOT32:
120 			case R_386_PLT32:
121 			case R_386_GOTPC:
122 				P = image->text_region.delta + rel[i].r_offset;
123 				TRACE(("P %p\n", (void *)P));
124 				break;
125 		}
126 
127 		switch (ELF32_R_TYPE(rel[i].r_info)) {
128 			case R_386_NONE:
129 				continue;
130 			case R_386_32:
131 				finalAddress = S + A;
132 				break;
133 			case R_386_PC32:
134 				finalAddress = S + A - P;
135 				break;
136 			case R_386_RELATIVE:
137 				// B + A;
138 				finalAddress = image->text_region.delta + A;
139 				break;
140 			case R_386_JMP_SLOT:
141 			case R_386_GLOB_DAT:
142 				finalAddress = S;
143 				break;
144 
145 			default:
146 				dprintf("arch_elf_relocate_rel: unhandled relocation type %d\n",
147 					ELF32_R_TYPE(rel[i].r_info));
148 				return B_BAD_DATA;
149 		}
150 
151 		resolveAddress = (addr_t *)(image->text_region.delta + rel[i].r_offset);
152 #ifndef _BOOT_MODE
153 		if (!is_in_image(image, (addr_t)resolveAddress)) {
154 			dprintf("arch_elf_relocate_rel: invalid offset %#lx\n",
155 				rel[i].r_offset);
156 			return B_BAD_ADDRESS;
157 		}
158 #endif
159 		*resolveAddress = finalAddress;
160 		TRACE(("-> offset %#lx = %#lx\n",
161 			(image->text_region.delta + rel[i].r_offset), finalAddress));
162 	}
163 
164 	return B_NO_ERROR;
165 }
166 
167 
168 #ifdef _BOOT_MODE
169 status_t
170 boot_arch_elf_relocate_rela(struct preloaded_image *image,
171 	struct Elf32_Rela *rel, int relLength)
172 #else
173 int
174 arch_elf_relocate_rela(struct elf_image_info *image,
175 	struct elf_image_info *resolveImage, struct Elf32_Rela *rel, int relLength)
176 #endif
177 {
178 	dprintf("arch_elf_relocate_rela: not supported on x86\n");
179 	return B_ERROR;
180 }
181 
182