xref: /haiku/src/system/runtime_loader/arch/x86_64/arch_relocate.cpp (revision c237c4ce593ee823d9867fd997e51e4c447f5623)
1 /*
2  * Copyright 2012, Alex Smith, alex@alex-smith.me.uk.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "runtime_loader_private.h"
8 
9 #include <runtime_loader.h>
10 
11 #include <string.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 
15 
16 static status_t
17 relocate_rela(image_t* rootImage, image_t* image, Elf64_Rela* rel,
18 	size_t relLength, SymbolLookupCache* cache)
19 {
20 	for (size_t i = 0; i < relLength / sizeof(Elf64_Rela); i++) {
21 		int type = ELF64_R_TYPE(rel[i].r_info);
22 		int symIndex = ELF64_R_SYM(rel[i].r_info);
23 		Elf64_Addr symAddr = 0;
24 		image_t* symbolImage = NULL;
25 
26 		// Resolve the symbol, if any.
27 		if (symIndex != 0) {
28 			Elf64_Sym* sym = SYMBOL(image, symIndex);
29 
30 			status_t status = resolve_symbol(rootImage, image, sym, cache,
31 				&symAddr, &symbolImage);
32 			if (status != B_OK) {
33 				TRACE(("resolve symbol \"%s\" returned: %" B_PRId32 "\n",
34 					SYMNAME(image, sym), status));
35 				printf("resolve symbol \"%s\" returned: %" B_PRId32 "\n",
36 					SYMNAME(image, sym), status);
37 				return status;
38 			}
39 		}
40 
41 		// Address of the relocation.
42 		Elf64_Addr relocAddr = image->regions[0].delta + rel[i].r_offset;
43 
44 		// Calculate the relocation value.
45 		Elf64_Addr relocValue;
46 		switch (type) {
47 			case R_X86_64_NONE:
48 				continue;
49 			case R_X86_64_64:
50 			case R_X86_64_GLOB_DAT:
51 			case R_X86_64_JUMP_SLOT:
52 				relocValue = symAddr + rel[i].r_addend;
53 				break;
54 			case R_X86_64_PC32:
55 				relocValue = symAddr + rel[i].r_addend - rel[i].r_offset;
56 				break;
57 			case R_X86_64_RELATIVE:
58 				relocValue = image->regions[0].delta + rel[i].r_addend;
59 				break;
60 			case R_X86_64_DTPMOD64:
61 				relocValue = symbolImage == NULL
62 							? image->dso_tls_id : symbolImage->dso_tls_id;
63 				break;
64 			case R_X86_64_DTPOFF32:
65 			case R_X86_64_DTPOFF64:
66 				relocValue = symAddr;
67 				break;
68 			default:
69 				TRACE(("unhandled relocation type %d\n", type));
70 				return B_BAD_DATA;
71 		}
72 
73 		if (type == R_X86_64_PC32 || type == R_X86_64_DTPOFF32)
74 			*(Elf32_Addr *)relocAddr = relocValue;
75 		else
76 			*(Elf64_Addr *)relocAddr = relocValue;
77 	}
78 
79 	return B_OK;
80 }
81 
82 
83 status_t
84 arch_relocate_image(image_t* rootImage, image_t* image,
85 	SymbolLookupCache* cache)
86 {
87 	status_t status;
88 
89 	// No REL on x86_64.
90 
91 	// Perform RELA relocations.
92 	if (image->rela) {
93 		status = relocate_rela(rootImage, image, image->rela, image->rela_len,
94 			cache);
95 		if (status != B_OK)
96 			return status;
97 	}
98 
99 	// PLT relocations (they are RELA on x86_64).
100 	if (image->pltrel) {
101 		status = relocate_rela(rootImage, image, (Elf64_Rela*)image->pltrel,
102 			image->pltrel_len, cache);
103 		if (status != B_OK)
104 			return status;
105 	}
106 
107 	return B_OK;
108 }
109