Linux Audio

Check our new training course

Linux kernel drivers training

Mar 31-Apr 9, 2025, special US time zones
Register
Loading...
v4.17
 
  1/*
  2 * Copyright (C) 2015 Imagination Technologies
  3 * Author: Alex Smith <alex.smith@imgtec.com>
  4 *
  5 * This program is free software; you can redistribute it and/or modify it
  6 * under the terms of the GNU General Public License as published by the
  7 * Free Software Foundation;  either version 2 of the  License, or (at your
  8 * option) any later version.
  9 */
 10
 11static inline bool FUNC(patch_vdso)(const char *path, void *vdso)
 12{
 13	const ELF(Ehdr) *ehdr = vdso;
 14	void *shdrs;
 15	ELF(Shdr) *shdr;
 16	char *shstrtab, *name;
 17	uint16_t sh_count, sh_entsize, i;
 18	unsigned int local_gotno, symtabno, gotsym;
 19	ELF(Dyn) *dyn = NULL;
 20
 21	shdrs = vdso + FUNC(swap_uint)(ehdr->e_shoff);
 22	sh_count = swap_uint16(ehdr->e_shnum);
 23	sh_entsize = swap_uint16(ehdr->e_shentsize);
 24
 25	shdr = shdrs + (sh_entsize * swap_uint16(ehdr->e_shstrndx));
 26	shstrtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
 27
 28	for (i = 0; i < sh_count; i++) {
 29		shdr = shdrs + (i * sh_entsize);
 30		name = shstrtab + swap_uint32(shdr->sh_name);
 31
 32		/*
 33		 * Ensure there are no relocation sections - ld.so does not
 34		 * relocate the VDSO so if there are relocations things will
 35		 * break.
 36		 */
 37		switch (swap_uint32(shdr->sh_type)) {
 38		case SHT_REL:
 39		case SHT_RELA:
 40			fprintf(stderr,
 41				"%s: '%s' contains relocation sections\n",
 42				program_name, path);
 43			return false;
 44		case SHT_DYNAMIC:
 45			dyn = vdso + FUNC(swap_uint)(shdr->sh_offset);
 46			break;
 47		}
 48
 49		/* Check for existing sections. */
 50		if (strcmp(name, ".MIPS.abiflags") == 0) {
 51			fprintf(stderr,
 52				"%s: '%s' already contains a '.MIPS.abiflags' section\n",
 53				program_name, path);
 54			return false;
 55		}
 56
 57		if (strcmp(name, ".mips_abiflags") == 0) {
 58			strcpy(name, ".MIPS.abiflags");
 59			shdr->sh_type = swap_uint32(SHT_MIPS_ABIFLAGS);
 60			shdr->sh_entsize = shdr->sh_size;
 61		}
 62	}
 63
 64	/*
 65	 * Ensure the GOT has no entries other than the standard 2, for the same
 66	 * reason we check that there's no relocation sections above.
 67	 * The standard two entries are:
 68	 * - Lazy resolver
 69	 * - Module pointer
 70	 */
 71	if (dyn) {
 72		local_gotno = symtabno = gotsym = 0;
 73
 74		while (FUNC(swap_uint)(dyn->d_tag) != DT_NULL) {
 75			switch (FUNC(swap_uint)(dyn->d_tag)) {
 76			/*
 77			 * This member holds the number of local GOT entries.
 78			 */
 79			case DT_MIPS_LOCAL_GOTNO:
 80				local_gotno = FUNC(swap_uint)(dyn->d_un.d_val);
 81				break;
 82			/*
 83			 * This member holds the number of entries in the
 84			 * .dynsym section.
 85			 */
 86			case DT_MIPS_SYMTABNO:
 87				symtabno = FUNC(swap_uint)(dyn->d_un.d_val);
 88				break;
 89			/*
 90			 * This member holds the index of the first dynamic
 91			 * symbol table entry that corresponds to an entry in
 92			 * the GOT.
 93			 */
 94			case DT_MIPS_GOTSYM:
 95				gotsym = FUNC(swap_uint)(dyn->d_un.d_val);
 96				break;
 97			}
 98
 99			dyn++;
100		}
101
102		if (local_gotno > 2 || symtabno - gotsym) {
103			fprintf(stderr,
104				"%s: '%s' contains unexpected GOT entries\n",
105				program_name, path);
106			return false;
107		}
108	}
109
110	return true;
111}
112
113static inline bool FUNC(get_symbols)(const char *path, void *vdso)
114{
115	const ELF(Ehdr) *ehdr = vdso;
116	void *shdrs, *symtab;
117	ELF(Shdr) *shdr;
118	const ELF(Sym) *sym;
119	char *strtab, *name;
120	uint16_t sh_count, sh_entsize, st_count, st_entsize, i, j;
121	uint64_t offset;
122	uint32_t flags;
123
124	shdrs = vdso + FUNC(swap_uint)(ehdr->e_shoff);
125	sh_count = swap_uint16(ehdr->e_shnum);
126	sh_entsize = swap_uint16(ehdr->e_shentsize);
127
128	for (i = 0; i < sh_count; i++) {
129		shdr = shdrs + (i * sh_entsize);
130
131		if (swap_uint32(shdr->sh_type) == SHT_SYMTAB)
132			break;
133	}
134
135	if (i == sh_count) {
136		fprintf(stderr, "%s: '%s' has no symbol table\n", program_name,
137			path);
138		return false;
139	}
140
141	/* Get flags */
142	flags = swap_uint32(ehdr->e_flags);
143	if (elf_class == ELFCLASS64)
144		elf_abi = ABI_N64;
145	else if (flags & EF_MIPS_ABI2)
146		elf_abi = ABI_N32;
147	else
148		elf_abi = ABI_O32;
149
150	/* Get symbol table. */
151	symtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
152	st_entsize = FUNC(swap_uint)(shdr->sh_entsize);
153	st_count = FUNC(swap_uint)(shdr->sh_size) / st_entsize;
154
155	/* Get string table. */
156	shdr = shdrs + (swap_uint32(shdr->sh_link) * sh_entsize);
157	strtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
158
159	/* Write offsets for symbols needed by the kernel. */
160	for (i = 0; vdso_symbols[i].name; i++) {
161		if (!(vdso_symbols[i].abis & elf_abi))
162			continue;
163
164		for (j = 0; j < st_count; j++) {
165			sym = symtab + (j * st_entsize);
166			name = strtab + swap_uint32(sym->st_name);
167
168			if (!strcmp(name, vdso_symbols[i].name)) {
169				offset = FUNC(swap_uint)(sym->st_value);
170
171				fprintf(out_file,
172					"\t.%s = 0x%" PRIx64 ",\n",
173					vdso_symbols[i].offset_name, offset);
174				break;
175			}
176		}
177
178		if (j == st_count) {
179			fprintf(stderr,
180				"%s: '%s' is missing required symbol '%s'\n",
181				program_name, path, vdso_symbols[i].name);
182			return false;
183		}
184	}
185
186	return true;
187}
v6.8
  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
  7static 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
 58static 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}