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
16static status_t
17relocate_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
83status_t
84arch_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