1/*
2 * Copyright 2012-2018, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Ithamar R. Adema <ithamar@upgrade-android.com>
7 */
8
9#include <string.h>
10#include <stdio.h>
11#include <stdlib.h>
12
13#include "runtime_loader_private.h"
14
15#include <runtime_loader.h>
16
17
18static status_t
19relocate_rela(image_t* rootImage, image_t* image, Elf64_Rela* rel,
20	size_t relLength, SymbolLookupCache* cache)
21{
22	for (size_t i = 0; i < relLength / sizeof(Elf64_Rela); i++) {
23		int type = ELF64_R_TYPE(rel[i].r_info);
24		int symIndex = ELF64_R_SYM(rel[i].r_info);
25		Elf64_Addr symAddr = 0;
26		image_t* symbolImage = NULL;
27
28		// Resolve the symbol, if any.
29		if (symIndex != 0) {
30			Elf64_Sym* sym = SYMBOL(image, symIndex);
31
32			status_t status = resolve_symbol(rootImage, image, sym, cache,
33				&symAddr, &symbolImage);
34			if (status != B_OK) {
35				TRACE(("resolve symbol \"%s\" returned: %" B_PRId32 "\n",
36					SYMNAME(image, sym), status));
37				printf("resolve symbol \"%s\" returned: %" B_PRId32 "\n",
38					SYMNAME(image, sym), status);
39				return status;
40			}
41		}
42
43		// Address of the relocation.
44		Elf64_Addr relocAddr = image->regions[0].delta + rel[i].r_offset;
45
46		// Calculate the relocation value.
47		Elf64_Addr relocValue;
48		switch (type) {
49			case R_RISCV_NONE:
50				continue;
51			case R_RISCV_64:
52			case R_RISCV_JUMP_SLOT:
53				relocValue = symAddr + rel[i].r_addend;
54				break;
55			case R_RISCV_RELATIVE:
56				relocValue = image->regions[0].delta + rel[i].r_addend;
57				break;
58			case R_RISCV_TLS_DTPMOD64:
59				relocValue = symbolImage == NULL
60							? image->dso_tls_id : symbolImage->dso_tls_id;
61				break;
62			case R_RISCV_TLS_DTPREL64:
63				relocValue = symAddr;
64				break;
65			default:
66				TRACE(("unhandled relocation type %d\n", type));
67				return B_BAD_DATA;
68		}
69
70		*(Elf64_Addr *)relocAddr = relocValue;
71	}
72
73	return B_OK;
74}
75
76
77status_t
78arch_relocate_image(image_t* rootImage, image_t* image,
79	SymbolLookupCache* cache)
80{
81	status_t status;
82
83	// Perform RELA relocations.
84	if (image->rela) {
85		status = relocate_rela(rootImage, image, image->rela, image->rela_len,
86			cache);
87		if (status != B_OK)
88			return status;
89	}
90
91	// PLT relocations (they are RELA on riscv64).
92	if (image->pltrel) {
93		status = relocate_rela(rootImage, image, (Elf64_Rela*)image->pltrel,
94			image->pltrel_len, cache);
95		if (status != B_OK)
96			return status;
97	}
98
99	return B_OK;
100}
101