Pull x86 cdso updates from Peter Anvin: "Vdso cleanups and improvements largely from Andy Lutomirski. This makes the vdso a lot less ''special''" * 'x86/vdso' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/vdso, build: Make LE access macros clearer, host-safe x86/vdso, build: Fix cross-compilation from big-endian architectures x86/vdso, build: When vdso2c fails, unlink the output x86, vdso: Fix an OOPS accessing the HPET mapping w/o an HPET x86, mm: Replace arch_vma_name with vm_ops->name for vsyscalls x86, mm: Improve _install_special_mapping and fix x86 vdso naming mm, fs: Add vm_ops->name as an alternative to arch_vma_name x86, vdso: Fix an OOPS accessing the HPET mapping w/o an HPET x86, vdso: Remove vestiges of VDSO_PRELINK and some outdated comments x86, vdso: Move the vvar and hpet mappings next to the 64-bit vDSO x86, vdso: Move the 32-bit vdso special pages after the text x86, vdso: Reimplement vdso.so preparation in build-time C x86, vdso: Move syscall and sysenter setup into kernel/cpu/common.c x86, vdso: Clean up 32-bit vs 64-bit vdso params x86, mm: Ensure correct alignment of the fixmaptirimbino
commit
a0abcf2e8f
@ -1,11 +0,0 @@ |
||||
#ifndef _ASM_X86_VDSO32_H |
||||
#define _ASM_X86_VDSO32_H |
||||
|
||||
#define VDSO_BASE_PAGE 0 |
||||
#define VDSO_VVAR_PAGE 1 |
||||
#define VDSO_HPET_PAGE 2 |
||||
#define VDSO_PAGES 3 |
||||
#define VDSO_PREV_PAGES 2 |
||||
#define VDSO_OFFSET(x) ((x) * PAGE_SIZE) |
||||
|
||||
#endif |
@ -1,8 +1,7 @@ |
||||
vdso.lds |
||||
vdso-syms.lds |
||||
vdsox32.lds |
||||
vdsox32-syms.lds |
||||
vdso32-syms.lds |
||||
vdso32-syscall-syms.lds |
||||
vdso32-sysenter-syms.lds |
||||
vdso32-int80-syms.lds |
||||
vdso-image-*.c |
||||
vdso2c |
||||
|
@ -1,3 +0,0 @@ |
||||
#include <asm/vdso.h> |
||||
|
||||
DEFINE_VDSO_IMAGE(vdso, "arch/x86/vdso/vdso.so") |
@ -0,0 +1,173 @@ |
||||
#include <inttypes.h> |
||||
#include <stdint.h> |
||||
#include <unistd.h> |
||||
#include <stdarg.h> |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <fcntl.h> |
||||
#include <err.h> |
||||
|
||||
#include <sys/mman.h> |
||||
#include <sys/types.h> |
||||
|
||||
#include <linux/elf.h> |
||||
#include <linux/types.h> |
||||
|
||||
const char *outfilename; |
||||
|
||||
/* Symbols that we need in vdso2c. */ |
||||
enum { |
||||
sym_vvar_page, |
||||
sym_hpet_page, |
||||
sym_end_mapping, |
||||
}; |
||||
|
||||
const int special_pages[] = { |
||||
sym_vvar_page, |
||||
sym_hpet_page, |
||||
}; |
||||
|
||||
char const * const required_syms[] = { |
||||
[sym_vvar_page] = "vvar_page", |
||||
[sym_hpet_page] = "hpet_page", |
||||
[sym_end_mapping] = "end_mapping", |
||||
"VDSO32_NOTE_MASK", |
||||
"VDSO32_SYSENTER_RETURN", |
||||
"__kernel_vsyscall", |
||||
"__kernel_sigreturn", |
||||
"__kernel_rt_sigreturn", |
||||
}; |
||||
|
||||
__attribute__((format(printf, 1, 2))) __attribute__((noreturn)) |
||||
static void fail(const char *format, ...) |
||||
{ |
||||
va_list ap; |
||||
va_start(ap, format); |
||||
fprintf(stderr, "Error: "); |
||||
vfprintf(stderr, format, ap); |
||||
unlink(outfilename); |
||||
exit(1); |
||||
va_end(ap); |
||||
} |
||||
|
||||
/*
|
||||
* Evil macros to do a little-endian read. |
||||
*/ |
||||
#define GLE(x, bits, ifnot) \ |
||||
__builtin_choose_expr( \
|
||||
(sizeof(x) == bits/8), \
|
||||
(__typeof__(x))le##bits##toh(x), ifnot) |
||||
|
||||
extern void bad_get_le(uint64_t); |
||||
#define LAST_LE(x) \ |
||||
__builtin_choose_expr(sizeof(x) == 1, (x), bad_get_le(x)) |
||||
|
||||
#define GET_LE(x) \ |
||||
GLE(x, 64, GLE(x, 32, GLE(x, 16, LAST_LE(x)))) |
||||
|
||||
#define NSYMS (sizeof(required_syms) / sizeof(required_syms[0])) |
||||
|
||||
#define BITS 64 |
||||
#define GOFUNC go64 |
||||
#define Elf_Ehdr Elf64_Ehdr |
||||
#define Elf_Shdr Elf64_Shdr |
||||
#define Elf_Phdr Elf64_Phdr |
||||
#define Elf_Sym Elf64_Sym |
||||
#define Elf_Dyn Elf64_Dyn |
||||
#include "vdso2c.h" |
||||
#undef BITS |
||||
#undef GOFUNC |
||||
#undef Elf_Ehdr |
||||
#undef Elf_Shdr |
||||
#undef Elf_Phdr |
||||
#undef Elf_Sym |
||||
#undef Elf_Dyn |
||||
|
||||
#define BITS 32 |
||||
#define GOFUNC go32 |
||||
#define Elf_Ehdr Elf32_Ehdr |
||||
#define Elf_Shdr Elf32_Shdr |
||||
#define Elf_Phdr Elf32_Phdr |
||||
#define Elf_Sym Elf32_Sym |
||||
#define Elf_Dyn Elf32_Dyn |
||||
#include "vdso2c.h" |
||||
#undef BITS |
||||
#undef GOFUNC |
||||
#undef Elf_Ehdr |
||||
#undef Elf_Shdr |
||||
#undef Elf_Phdr |
||||
#undef Elf_Sym |
||||
#undef Elf_Dyn |
||||
|
||||
static void go(void *addr, size_t len, FILE *outfile, const char *name) |
||||
{ |
||||
Elf64_Ehdr *hdr = (Elf64_Ehdr *)addr; |
||||
|
||||
if (hdr->e_ident[EI_CLASS] == ELFCLASS64) { |
||||
go64(addr, len, outfile, name); |
||||
} else if (hdr->e_ident[EI_CLASS] == ELFCLASS32) { |
||||
go32(addr, len, outfile, name); |
||||
} else { |
||||
fail("unknown ELF class\n"); |
||||
} |
||||
} |
||||
|
||||
int main(int argc, char **argv) |
||||
{ |
||||
int fd; |
||||
off_t len; |
||||
void *addr; |
||||
FILE *outfile; |
||||
char *name, *tmp; |
||||
int namelen; |
||||
|
||||
if (argc != 3) { |
||||
printf("Usage: vdso2c INPUT OUTPUT\n"); |
||||
return 1; |
||||
} |
||||
|
||||
/*
|
||||
* Figure out the struct name. If we're writing to a .so file, |
||||
* generate raw output insted. |
||||
*/ |
||||
name = strdup(argv[2]); |
||||
namelen = strlen(name); |
||||
if (namelen >= 3 && !strcmp(name + namelen - 3, ".so")) { |
||||
name = NULL; |
||||
} else { |
||||
tmp = strrchr(name, '/'); |
||||
if (tmp) |
||||
name = tmp + 1; |
||||
tmp = strchr(name, '.'); |
||||
if (tmp) |
||||
*tmp = '\0'; |
||||
for (tmp = name; *tmp; tmp++) |
||||
if (*tmp == '-') |
||||
*tmp = '_'; |
||||
} |
||||
|
||||
fd = open(argv[1], O_RDONLY); |
||||
if (fd == -1) |
||||
err(1, "%s", argv[1]); |
||||
|
||||
len = lseek(fd, 0, SEEK_END); |
||||
if (len == (off_t)-1) |
||||
err(1, "lseek"); |
||||
|
||||
addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); |
||||
if (addr == MAP_FAILED) |
||||
err(1, "mmap"); |
||||
|
||||
outfilename = argv[2]; |
||||
outfile = fopen(outfilename, "w"); |
||||
if (!outfile) |
||||
err(1, "%s", argv[2]); |
||||
|
||||
go(addr, (size_t)len, outfile, name); |
||||
|
||||
munmap(addr, len); |
||||
fclose(outfile); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,163 @@ |
||||
/*
|
||||
* This file is included twice from vdso2c.c. It generates code for 32-bit |
||||
* and 64-bit vDSOs. We need both for 64-bit builds, since 32-bit vDSOs |
||||
* are built for 32-bit userspace. |
||||
*/ |
||||
|
||||
static void GOFUNC(void *addr, size_t len, FILE *outfile, const char *name) |
||||
{ |
||||
int found_load = 0; |
||||
unsigned long load_size = -1; /* Work around bogus warning */ |
||||
unsigned long data_size; |
||||
Elf_Ehdr *hdr = (Elf_Ehdr *)addr; |
||||
int i; |
||||
unsigned long j; |
||||
Elf_Shdr *symtab_hdr = NULL, *strtab_hdr, *secstrings_hdr, |
||||
*alt_sec = NULL; |
||||
Elf_Dyn *dyn = 0, *dyn_end = 0; |
||||
const char *secstrings; |
||||
uint64_t syms[NSYMS] = {}; |
||||
|
||||
Elf_Phdr *pt = (Elf_Phdr *)(addr + GET_LE(hdr->e_phoff)); |
||||
|
||||
/* Walk the segment table. */ |
||||
for (i = 0; i < GET_LE(hdr->e_phnum); i++) { |
||||
if (GET_LE(pt[i].p_type) == PT_LOAD) { |
||||
if (found_load) |
||||
fail("multiple PT_LOAD segs\n"); |
||||
|
||||
if (GET_LE(pt[i].p_offset) != 0 || |
||||
GET_LE(pt[i].p_vaddr) != 0) |
||||
fail("PT_LOAD in wrong place\n"); |
||||
|
||||
if (GET_LE(pt[i].p_memsz) != GET_LE(pt[i].p_filesz)) |
||||
fail("cannot handle memsz != filesz\n"); |
||||
|
||||
load_size = GET_LE(pt[i].p_memsz); |
||||
found_load = 1; |
||||
} else if (GET_LE(pt[i].p_type) == PT_DYNAMIC) { |
||||
dyn = addr + GET_LE(pt[i].p_offset); |
||||
dyn_end = addr + GET_LE(pt[i].p_offset) + |
||||
GET_LE(pt[i].p_memsz); |
||||
} |
||||
} |
||||
if (!found_load) |
||||
fail("no PT_LOAD seg\n"); |
||||
data_size = (load_size + 4095) / 4096 * 4096; |
||||
|
||||
/* Walk the dynamic table */ |
||||
for (i = 0; dyn + i < dyn_end && |
||||
GET_LE(dyn[i].d_tag) != DT_NULL; i++) { |
||||
typeof(dyn[i].d_tag) tag = GET_LE(dyn[i].d_tag); |
||||
if (tag == DT_REL || tag == DT_RELSZ || |
||||
tag == DT_RELENT || tag == DT_TEXTREL) |
||||
fail("vdso image contains dynamic relocations\n"); |
||||
} |
||||
|
||||
/* Walk the section table */ |
||||
secstrings_hdr = addr + GET_LE(hdr->e_shoff) + |
||||
GET_LE(hdr->e_shentsize)*GET_LE(hdr->e_shstrndx); |
||||
secstrings = addr + GET_LE(secstrings_hdr->sh_offset); |
||||
for (i = 0; i < GET_LE(hdr->e_shnum); i++) { |
||||
Elf_Shdr *sh = addr + GET_LE(hdr->e_shoff) + |
||||
GET_LE(hdr->e_shentsize) * i; |
||||
if (GET_LE(sh->sh_type) == SHT_SYMTAB) |
||||
symtab_hdr = sh; |
||||
|
||||
if (!strcmp(secstrings + GET_LE(sh->sh_name), |
||||
".altinstructions")) |
||||
alt_sec = sh; |
||||
} |
||||
|
||||
if (!symtab_hdr) |
||||
fail("no symbol table\n"); |
||||
|
||||
strtab_hdr = addr + GET_LE(hdr->e_shoff) + |
||||
GET_LE(hdr->e_shentsize) * GET_LE(symtab_hdr->sh_link); |
||||
|
||||
/* Walk the symbol table */ |
||||
for (i = 0; |
||||
i < GET_LE(symtab_hdr->sh_size) / GET_LE(symtab_hdr->sh_entsize); |
||||
i++) { |
||||
int k; |
||||
Elf_Sym *sym = addr + GET_LE(symtab_hdr->sh_offset) + |
||||
GET_LE(symtab_hdr->sh_entsize) * i; |
||||
const char *name = addr + GET_LE(strtab_hdr->sh_offset) + |
||||
GET_LE(sym->st_name); |
||||
for (k = 0; k < NSYMS; k++) { |
||||
if (!strcmp(name, required_syms[k])) { |
||||
if (syms[k]) { |
||||
fail("duplicate symbol %s\n", |
||||
required_syms[k]); |
||||
} |
||||
syms[k] = GET_LE(sym->st_value); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* Validate mapping addresses. */ |
||||
for (i = 0; i < sizeof(special_pages) / sizeof(special_pages[0]); i++) { |
||||
if (!syms[i]) |
||||
continue; /* The mapping isn't used; ignore it. */ |
||||
|
||||
if (syms[i] % 4096) |
||||
fail("%s must be a multiple of 4096\n", |
||||
required_syms[i]); |
||||
if (syms[i] < data_size) |
||||
fail("%s must be after the text mapping\n", |
||||
required_syms[i]); |
||||
if (syms[sym_end_mapping] < syms[i] + 4096) |
||||
fail("%s overruns end_mapping\n", required_syms[i]); |
||||
} |
||||
if (syms[sym_end_mapping] % 4096) |
||||
fail("end_mapping must be a multiple of 4096\n"); |
||||
|
||||
/* Remove sections. */ |
||||
hdr->e_shoff = 0; |
||||
hdr->e_shentsize = 0; |
||||
hdr->e_shnum = 0; |
||||
hdr->e_shstrndx = htole16(SHN_UNDEF); |
||||
|
||||
if (!name) { |
||||
fwrite(addr, load_size, 1, outfile); |
||||
return; |
||||
} |
||||
|
||||
fprintf(outfile, "/* AUTOMATICALLY GENERATED -- DO NOT EDIT */\n\n"); |
||||
fprintf(outfile, "#include <linux/linkage.h>\n"); |
||||
fprintf(outfile, "#include <asm/page_types.h>\n"); |
||||
fprintf(outfile, "#include <asm/vdso.h>\n"); |
||||
fprintf(outfile, "\n"); |
||||
fprintf(outfile, |
||||
"static unsigned char raw_data[%lu] __page_aligned_data = {", |
||||
data_size); |
||||
for (j = 0; j < load_size; j++) { |
||||
if (j % 10 == 0) |
||||
fprintf(outfile, "\n\t"); |
||||
fprintf(outfile, "0x%02X, ", (int)((unsigned char *)addr)[j]); |
||||
} |
||||
fprintf(outfile, "\n};\n\n"); |
||||
|
||||
fprintf(outfile, "static struct page *pages[%lu];\n\n", |
||||
data_size / 4096); |
||||
|
||||
fprintf(outfile, "const struct vdso_image %s = {\n", name); |
||||
fprintf(outfile, "\t.data = raw_data,\n"); |
||||
fprintf(outfile, "\t.size = %lu,\n", data_size); |
||||
fprintf(outfile, "\t.text_mapping = {\n"); |
||||
fprintf(outfile, "\t\t.name = \"[vdso]\",\n"); |
||||
fprintf(outfile, "\t\t.pages = pages,\n"); |
||||
fprintf(outfile, "\t},\n"); |
||||
if (alt_sec) { |
||||
fprintf(outfile, "\t.alt = %lu,\n", |
||||
(unsigned long)GET_LE(alt_sec->sh_offset)); |
||||
fprintf(outfile, "\t.alt_len = %lu,\n", |
||||
(unsigned long)GET_LE(alt_sec->sh_size)); |
||||
} |
||||
for (i = 0; i < NSYMS; i++) { |
||||
if (syms[i]) |
||||
fprintf(outfile, "\t.sym_%s = 0x%" PRIx64 ",\n", |
||||
required_syms[i], syms[i]); |
||||
} |
||||
fprintf(outfile, "};\n"); |
||||
} |
@ -1,9 +0,0 @@ |
||||
#include <asm/vdso.h> |
||||
|
||||
DEFINE_VDSO_IMAGE(vdso32_int80, "arch/x86/vdso/vdso32-int80.so") |
||||
|
||||
#ifdef CONFIG_COMPAT |
||||
DEFINE_VDSO_IMAGE(vdso32_syscall, "arch/x86/vdso/vdso32-syscall.so") |
||||
#endif |
||||
|
||||
DEFINE_VDSO_IMAGE(vdso32_sysenter, "arch/x86/vdso/vdso32-sysenter.so") |
@ -1,3 +0,0 @@ |
||||
#include <asm/vdso.h> |
||||
|
||||
DEFINE_VDSO_IMAGE(vdsox32, "arch/x86/vdso/vdsox32.so") |
Loading…
Reference in new issue