summaryrefslogtreecommitdiffstats
path: root/kexec/arch/x86_64/kexec-elf-rel-x86_64.c
blob: db85b443238de49589896beeb2ef44594eeb6f82 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <stdio.h>
#include <elf.h>
#include "../../kexec.h"
#include "../../kexec-elf.h"

int machine_verify_elf_rel(struct mem_ehdr *ehdr)
{
	if (ehdr->ei_data != ELFDATA2LSB) {
		return 0;
	}
	if (ehdr->ei_class != ELFCLASS64) {
		return 0;
	}
	if (ehdr->e_machine != EM_X86_64) {
		return 0;
	}
	return 1;
}

static const char *reloc_name(unsigned long r_type)
{
	static const char *r_name[] = {
	"R_X86_64_NONE",
	"R_X86_64_64",
	"R_X86_64_PC32",
	"R_X86_64_GOT32",
	"R_X86_64_PLT32",
	"R_X86_64_COPY",
	"R_X86_64_GLOB_DAT",
	"R_X86_64_JUMP_SLOT",
	"R_X86_64_RELATIVE",
	"R_X86_64_GOTPCREL",
	"R_X86_64_32",
	"R_X86_64_32S",
	"R_X86_64_16",
	"R_X86_64_PC16",
	"R_X86_64_8",
	"R_X86_64_PC8",
	"R_X86_64_DTPMOD64",
	"R_X86_64_DTPOFF64",
	"R_X86_64_TPOFF64",
	"R_X86_64_TLSGD",
	"R_X86_64_TLSLD",
	"R_X86_64_DTPOFF32",
	"R_X86_64_GOTTPOFF",
	"R_X86_64_TPOFF32",
	};
	static char buf[100];
	const char *name;
	if (r_type < (sizeof(r_name)/sizeof(r_name[0]))){
		name = r_name[r_type];
	}
	else {
		sprintf(buf, "R_X86_64_%lu", r_type);
		name = buf;
	}
	return name;
}

void machine_apply_elf_rel(struct mem_ehdr *UNUSED(ehdr),
	struct mem_sym *UNUSED(sym), unsigned long r_type, void *location,
	unsigned long address, unsigned long value)
{
	dbgprintf("%s\n", reloc_name(r_type));
	switch(r_type) {
	case R_X86_64_NONE:
		break;
	case R_X86_64_64:
		*(uint64_t *)location = value;
		break;
	case R_X86_64_32:
		*(uint32_t *)location = value;
		if (value != *(uint32_t *)location)
			goto overflow;
		break;
	case R_X86_64_32S:
		*(uint32_t *)location = value;
		if ((int64_t)value != *(int32_t *)location)
			goto overflow;
		break;
	case R_X86_64_PC32: 
	case R_X86_64_PLT32:
		*(uint32_t *)location = value - address;
		break;
	default:
		die("Unhandled rela relocation: %s\n", reloc_name(r_type));
		break;
	}
	return;
 overflow:
	die("overflow in relocation type %s val %lx\n",
		reloc_name(r_type), value);
}