162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2015 Imagination Technologies
462306a36Sopenharmony_ci * Author: Alex Smith <alex.smith@imgtec.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_cistatic inline bool FUNC(patch_vdso)(const char *path, void *vdso)
862306a36Sopenharmony_ci{
962306a36Sopenharmony_ci	const ELF(Ehdr) *ehdr = vdso;
1062306a36Sopenharmony_ci	void *shdrs;
1162306a36Sopenharmony_ci	ELF(Shdr) *shdr;
1262306a36Sopenharmony_ci	char *shstrtab, *name;
1362306a36Sopenharmony_ci	uint16_t sh_count, sh_entsize, i;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci	shdrs = vdso + FUNC(swap_uint)(ehdr->e_shoff);
1662306a36Sopenharmony_ci	sh_count = swap_uint16(ehdr->e_shnum);
1762306a36Sopenharmony_ci	sh_entsize = swap_uint16(ehdr->e_shentsize);
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	shdr = shdrs + (sh_entsize * swap_uint16(ehdr->e_shstrndx));
2062306a36Sopenharmony_ci	shstrtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	for (i = 0; i < sh_count; i++) {
2362306a36Sopenharmony_ci		shdr = shdrs + (i * sh_entsize);
2462306a36Sopenharmony_ci		name = shstrtab + swap_uint32(shdr->sh_name);
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci		/*
2762306a36Sopenharmony_ci		 * Ensure there are no relocation sections - ld.so does not
2862306a36Sopenharmony_ci		 * relocate the VDSO so if there are relocations things will
2962306a36Sopenharmony_ci		 * break.
3062306a36Sopenharmony_ci		 */
3162306a36Sopenharmony_ci		switch (swap_uint32(shdr->sh_type)) {
3262306a36Sopenharmony_ci		case SHT_REL:
3362306a36Sopenharmony_ci		case SHT_RELA:
3462306a36Sopenharmony_ci			fprintf(stderr,
3562306a36Sopenharmony_ci				"%s: '%s' contains relocation sections\n",
3662306a36Sopenharmony_ci				program_name, path);
3762306a36Sopenharmony_ci			return false;
3862306a36Sopenharmony_ci		}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci		/* Check for existing sections. */
4162306a36Sopenharmony_ci		if (strcmp(name, ".MIPS.abiflags") == 0) {
4262306a36Sopenharmony_ci			fprintf(stderr,
4362306a36Sopenharmony_ci				"%s: '%s' already contains a '.MIPS.abiflags' section\n",
4462306a36Sopenharmony_ci				program_name, path);
4562306a36Sopenharmony_ci			return false;
4662306a36Sopenharmony_ci		}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci		if (strcmp(name, ".mips_abiflags") == 0) {
4962306a36Sopenharmony_ci			strcpy(name, ".MIPS.abiflags");
5062306a36Sopenharmony_ci			shdr->sh_type = swap_uint32(SHT_MIPS_ABIFLAGS);
5162306a36Sopenharmony_ci			shdr->sh_entsize = shdr->sh_size;
5262306a36Sopenharmony_ci		}
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	return true;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic inline bool FUNC(get_symbols)(const char *path, void *vdso)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	const ELF(Ehdr) *ehdr = vdso;
6162306a36Sopenharmony_ci	void *shdrs, *symtab;
6262306a36Sopenharmony_ci	ELF(Shdr) *shdr;
6362306a36Sopenharmony_ci	const ELF(Sym) *sym;
6462306a36Sopenharmony_ci	char *strtab, *name;
6562306a36Sopenharmony_ci	uint16_t sh_count, sh_entsize, st_count, st_entsize, i, j;
6662306a36Sopenharmony_ci	uint64_t offset;
6762306a36Sopenharmony_ci	uint32_t flags;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	shdrs = vdso + FUNC(swap_uint)(ehdr->e_shoff);
7062306a36Sopenharmony_ci	sh_count = swap_uint16(ehdr->e_shnum);
7162306a36Sopenharmony_ci	sh_entsize = swap_uint16(ehdr->e_shentsize);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	for (i = 0; i < sh_count; i++) {
7462306a36Sopenharmony_ci		shdr = shdrs + (i * sh_entsize);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci		if (swap_uint32(shdr->sh_type) == SHT_SYMTAB)
7762306a36Sopenharmony_ci			break;
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	if (i == sh_count) {
8162306a36Sopenharmony_ci		fprintf(stderr, "%s: '%s' has no symbol table\n", program_name,
8262306a36Sopenharmony_ci			path);
8362306a36Sopenharmony_ci		return false;
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/* Get flags */
8762306a36Sopenharmony_ci	flags = swap_uint32(ehdr->e_flags);
8862306a36Sopenharmony_ci	if (elf_class == ELFCLASS64)
8962306a36Sopenharmony_ci		elf_abi = ABI_N64;
9062306a36Sopenharmony_ci	else if (flags & EF_MIPS_ABI2)
9162306a36Sopenharmony_ci		elf_abi = ABI_N32;
9262306a36Sopenharmony_ci	else
9362306a36Sopenharmony_ci		elf_abi = ABI_O32;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	/* Get symbol table. */
9662306a36Sopenharmony_ci	symtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
9762306a36Sopenharmony_ci	st_entsize = FUNC(swap_uint)(shdr->sh_entsize);
9862306a36Sopenharmony_ci	st_count = FUNC(swap_uint)(shdr->sh_size) / st_entsize;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	/* Get string table. */
10162306a36Sopenharmony_ci	shdr = shdrs + (swap_uint32(shdr->sh_link) * sh_entsize);
10262306a36Sopenharmony_ci	strtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* Write offsets for symbols needed by the kernel. */
10562306a36Sopenharmony_ci	for (i = 0; vdso_symbols[i].name; i++) {
10662306a36Sopenharmony_ci		if (!(vdso_symbols[i].abis & elf_abi))
10762306a36Sopenharmony_ci			continue;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		for (j = 0; j < st_count; j++) {
11062306a36Sopenharmony_ci			sym = symtab + (j * st_entsize);
11162306a36Sopenharmony_ci			name = strtab + swap_uint32(sym->st_name);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci			if (!strcmp(name, vdso_symbols[i].name)) {
11462306a36Sopenharmony_ci				offset = FUNC(swap_uint)(sym->st_value);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci				fprintf(out_file,
11762306a36Sopenharmony_ci					"\t.%s = 0x%" PRIx64 ",\n",
11862306a36Sopenharmony_ci					vdso_symbols[i].offset_name, offset);
11962306a36Sopenharmony_ci				break;
12062306a36Sopenharmony_ci			}
12162306a36Sopenharmony_ci		}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci		if (j == st_count) {
12462306a36Sopenharmony_ci			fprintf(stderr,
12562306a36Sopenharmony_ci				"%s: '%s' is missing required symbol '%s'\n",
12662306a36Sopenharmony_ci				program_name, path, vdso_symbols[i].name);
12762306a36Sopenharmony_ci			return false;
12862306a36Sopenharmony_ci		}
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	return true;
13262306a36Sopenharmony_ci}
133