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
25		// Resolve the symbol, if any.
26		if (symIndex != 0) {
27			Elf64_Sym* sym = SYMBOL(image, symIndex);
28
29			status_t status = resolve_symbol(rootImage, image, sym, cache,
30				&symAddr);
31			if (status != B_OK) {
32				TRACE(("resolve symbol \"%s\" returned: %" B_PRId32 "\n",
33					SYMNAME(image, sym), status));
34				printf("resolve symbol \"%s\" returned: %" B_PRId32 "\n",
35					SYMNAME(image, sym), status);
36				return status;
37			}
38		}
39
40		// Address of the relocation.
41		Elf64_Addr relocAddr = image->regions[0].delta + rel[i].r_offset;
42
43		// Calculate the relocation value.
44		Elf64_Addr relocValue;
45		switch(type) {
46			case R_X86_64_NONE:
47				continue;
48			case R_X86_64_64:
49			case R_X86_64_GLOB_DAT:
50			case R_X86_64_JUMP_SLOT:
51				relocValue = symAddr + rel[i].r_addend;
52				break;
53			case R_X86_64_PC32:
54				relocValue = symAddr + rel[i].r_addend - rel[i].r_offset;
55				break;
56			case R_X86_64_RELATIVE:
57				relocValue = image->regions[0].delta + rel[i].r_addend;
58				break;
59			default:
60				TRACE(("unhandled relocation type %d\n", type));
61				return B_BAD_DATA;
62		}
63
64		*(Elf64_Addr *)relocAddr = relocValue;
65	}
66
67	return B_OK;
68}
69
70
71status_t
72arch_relocate_image(image_t* rootImage, image_t* image,
73	SymbolLookupCache* cache)
74{
75	status_t status;
76
77	// No REL on x86_64.
78
79	// Perform RELA relocations.
80	if (image->rela) {
81		status = relocate_rela(rootImage, image, image->rela, image->rela_len,
82			cache);
83		if (status != B_OK)
84			return status;
85	}
86
87	// PLT relocations (they are RELA on x86_64).
88	if (image->pltrel) {
89		status = relocate_rela(rootImage, image, (Elf64_Rela*)image->pltrel,
90			image->pltrel_len, cache);
91		if (status != B_OK)
92			return status;
93	}
94
95	return B_OK;
96}
97