xref: /openbmc/linux/arch/mips/vdso/genvdso.h (revision 3cf3cdea)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * Copyright (C) 2015 Imagination Technologies
4  * Author: Alex Smith <alex.smith@imgtec.com>
5  */
6 
7 static inline bool FUNC(patch_vdso)(const char *path, void *vdso)
8 {
9 	const ELF(Ehdr) *ehdr = vdso;
10 	void *shdrs;
11 	ELF(Shdr) *shdr;
12 	char *shstrtab, *name;
13 	uint16_t sh_count, sh_entsize, i;
14 
15 	shdrs = vdso + FUNC(swap_uint)(ehdr->e_shoff);
16 	sh_count = swap_uint16(ehdr->e_shnum);
17 	sh_entsize = swap_uint16(ehdr->e_shentsize);
18 
19 	shdr = shdrs + (sh_entsize * swap_uint16(ehdr->e_shstrndx));
20 	shstrtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
21 
22 	for (i = 0; i < sh_count; i++) {
23 		shdr = shdrs + (i * sh_entsize);
24 		name = shstrtab + swap_uint32(shdr->sh_name);
25 
26 		/*
27 		 * Ensure there are no relocation sections - ld.so does not
28 		 * relocate the VDSO so if there are relocations things will
29 		 * break.
30 		 */
31 		switch (swap_uint32(shdr->sh_type)) {
32 		case SHT_REL:
33 		case SHT_RELA:
34 			fprintf(stderr,
35 				"%s: '%s' contains relocation sections\n",
36 				program_name, path);
37 			return false;
38 		}
39 
40 		/* Check for existing sections. */
41 		if (strcmp(name, ".MIPS.abiflags") == 0) {
42 			fprintf(stderr,
43 				"%s: '%s' already contains a '.MIPS.abiflags' section\n",
44 				program_name, path);
45 			return false;
46 		}
47 
48 		if (strcmp(name, ".mips_abiflags") == 0) {
49 			strcpy(name, ".MIPS.abiflags");
50 			shdr->sh_type = swap_uint32(SHT_MIPS_ABIFLAGS);
51 			shdr->sh_entsize = shdr->sh_size;
52 		}
53 	}
54 
55 	return true;
56 }
57 
58 static inline bool FUNC(get_symbols)(const char *path, void *vdso)
59 {
60 	const ELF(Ehdr) *ehdr = vdso;
61 	void *shdrs, *symtab;
62 	ELF(Shdr) *shdr;
63 	const ELF(Sym) *sym;
64 	char *strtab, *name;
65 	uint16_t sh_count, sh_entsize, st_count, st_entsize, i, j;
66 	uint64_t offset;
67 	uint32_t flags;
68 
69 	shdrs = vdso + FUNC(swap_uint)(ehdr->e_shoff);
70 	sh_count = swap_uint16(ehdr->e_shnum);
71 	sh_entsize = swap_uint16(ehdr->e_shentsize);
72 
73 	for (i = 0; i < sh_count; i++) {
74 		shdr = shdrs + (i * sh_entsize);
75 
76 		if (swap_uint32(shdr->sh_type) == SHT_SYMTAB)
77 			break;
78 	}
79 
80 	if (i == sh_count) {
81 		fprintf(stderr, "%s: '%s' has no symbol table\n", program_name,
82 			path);
83 		return false;
84 	}
85 
86 	/* Get flags */
87 	flags = swap_uint32(ehdr->e_flags);
88 	if (elf_class == ELFCLASS64)
89 		elf_abi = ABI_N64;
90 	else if (flags & EF_MIPS_ABI2)
91 		elf_abi = ABI_N32;
92 	else
93 		elf_abi = ABI_O32;
94 
95 	/* Get symbol table. */
96 	symtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
97 	st_entsize = FUNC(swap_uint)(shdr->sh_entsize);
98 	st_count = FUNC(swap_uint)(shdr->sh_size) / st_entsize;
99 
100 	/* Get string table. */
101 	shdr = shdrs + (swap_uint32(shdr->sh_link) * sh_entsize);
102 	strtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
103 
104 	/* Write offsets for symbols needed by the kernel. */
105 	for (i = 0; vdso_symbols[i].name; i++) {
106 		if (!(vdso_symbols[i].abis & elf_abi))
107 			continue;
108 
109 		for (j = 0; j < st_count; j++) {
110 			sym = symtab + (j * st_entsize);
111 			name = strtab + swap_uint32(sym->st_name);
112 
113 			if (!strcmp(name, vdso_symbols[i].name)) {
114 				offset = FUNC(swap_uint)(sym->st_value);
115 
116 				fprintf(out_file,
117 					"\t.%s = 0x%" PRIx64 ",\n",
118 					vdso_symbols[i].offset_name, offset);
119 				break;
120 			}
121 		}
122 
123 		if (j == st_count) {
124 			fprintf(stderr,
125 				"%s: '%s' is missing required symbol '%s'\n",
126 				program_name, path, vdso_symbols[i].name);
127 			return false;
128 		}
129 	}
130 
131 	return true;
132 }
133