Commit 9a180727 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: kernel module loader.

Add missing/fix existing s390 relocations in the kernel module loader.
parent eebba6ad
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
* arch/s390/kernel/module.c - Kernel module help for s390. * arch/s390/kernel/module.c - Kernel module help for s390.
* *
* S390 version * S390 version
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation * Copyright (C) 2002, 2003 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
* Author(s): Arnd Bergmann (arndb@de.ibm.com) * Author(s): Arnd Bergmann (arndb@de.ibm.com)
* Martin Schwidefsky (schwidefsky@de.ibm.com) * Martin Schwidefsky (schwidefsky@de.ibm.com)
* *
...@@ -36,6 +37,9 @@ ...@@ -36,6 +37,9 @@
#define DEBUGP(fmt , ...) #define DEBUGP(fmt , ...)
#endif #endif
#define GOT_ENTRY_SIZE 4
#define PLT_ENTRY_SIZE 12
void *module_alloc(unsigned long size) void *module_alloc(unsigned long size)
{ {
if (size == 0) if (size == 0)
...@@ -51,109 +55,296 @@ void module_free(struct module *mod, void *module_region) ...@@ -51,109 +55,296 @@ void module_free(struct module *mod, void *module_region)
table entries. */ table entries. */
} }
int module_frob_arch_sections(Elf_Ehdr *hdr, static inline void
Elf_Shdr *sechdrs, check_rela(Elf32_Rela *rela, struct module *me)
char *secstrings,
struct module *mod)
{ {
// FIXME: add space needed for GOT/PLT struct mod_arch_syminfo *info;
info = me->arch.syminfo + ELF32_R_SYM (rela->r_info);
switch (ELF32_R_TYPE (rela->r_info)) {
case R_390_GOT12: /* 12 bit GOT offset. */
case R_390_GOT16: /* 16 bit GOT offset. */
case R_390_GOT32: /* 32 bit GOT offset. */
case R_390_GOTENT: /* 32 bit PC rel. to GOT entry shifted by 1. */
case R_390_GOTPLT12: /* 12 bit offset to jump slot. */
case R_390_GOTPLT16: /* 16 bit offset to jump slot. */
case R_390_GOTPLT32: /* 32 bit offset to jump slot. */
case R_390_GOTPLTENT: /* 32 bit rel. offset to jump slot >> 1. */
if (info->got_offset == -1UL) {
info->got_offset = me->arch.got_size;
me->arch.got_size += GOT_ENTRY_SIZE;
}
break;
case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */
case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */
case R_390_PLT32: /* 32 bit PC relative PLT address. */
case R_390_PLTOFF16: /* 16 bit offset from GOT to PLT. */
case R_390_PLTOFF32: /* 32 bit offset from GOT to PLT. */
if (info->plt_offset == -1UL) {
info->plt_offset = me->arch.plt_size;
me->arch.plt_size += PLT_ENTRY_SIZE;
}
break;
case R_390_COPY:
case R_390_GLOB_DAT:
case R_390_JMP_SLOT:
case R_390_RELATIVE:
/* Only needed if we want to support loading of
modules linked with -shared. */
break;
}
}
/*
* Account for GOT and PLT relocations. We can't add sections for
* got and plt but we can increase the core module size.
*/
int
module_frob_arch_sections(Elf32_Ehdr *hdr, Elf32_Shdr *sechdrs,
char *secstrings, struct module *me)
{
Elf32_Shdr *symtab;
Elf32_Sym *symbols;
Elf32_Rela *rela;
char *strings;
int nrela, i, j;
/* Find symbol table and string table. */
symtab = 0;
for (i = 0; i < hdr->e_shnum; i++)
switch (sechdrs[i].sh_type) {
case SHT_SYMTAB:
symtab = sechdrs + i;
break;
}
if (!symtab) {
printk(KERN_ERR "module %s: no symbol table\n", me->name);
return -ENOEXEC;
}
/* Allocate one syminfo structure per symbol. */
me->arch.nsyms = symtab->sh_size / sizeof(Elf32_Sym);
me->arch.syminfo = kmalloc(me->arch.nsyms *
sizeof(struct mod_arch_syminfo),
GFP_KERNEL);
if (!me->arch.syminfo)
return -ENOMEM;
symbols = (void *) hdr + symtab->sh_offset;
strings = (void *) hdr + sechdrs[symtab->sh_link].sh_offset;
for (i = 0; i < me->arch.nsyms; i++) {
if (symbols[i].st_shndx == SHN_UNDEF &&
strcmp(strings + symbols[i].st_name,
"_GLOBAL_OFFSET_TABLE_") == 0)
/* "Define" it as absolute. */
symbols[i].st_shndx = SHN_ABS;
me->arch.syminfo[i].got_offset = -1UL;
me->arch.syminfo[i].plt_offset = -1UL;
me->arch.syminfo[i].got_initialized = 0;
me->arch.syminfo[i].plt_initialized = 0;
}
/* Search for got/plt relocations. */
me->arch.got_size = me->arch.plt_size = 0;
for (i = 0; i < hdr->e_shnum; i++) {
if (sechdrs[i].sh_type != SHT_RELA)
continue;
nrela = sechdrs[i].sh_size / sizeof(Elf32_Rela);
rela = (void *) hdr + sechdrs[i].sh_offset;
for (j = 0; j < nrela; j++)
check_rela(rela + j, me);
}
/* Increase core size by size of got & plt and set start
offsets for got and plt. */
me->core_size = ALIGN(me->core_size, 4);
me->arch.got_offset = me->core_size;
me->core_size += me->arch.got_size;
me->arch.plt_offset = me->core_size;
me->core_size += me->arch.plt_size;
return 0; return 0;
} }
int apply_relocate(Elf_Shdr *sechdrs, int
const char *strtab, apply_relocate(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex,
unsigned int symindex, unsigned int relsec, struct module *me)
unsigned int relsec, {
printk(KERN_ERR "module %s: RELOCATION unsupported\n",
me->name);
return -ENOEXEC;
}
static inline int
apply_rela(Elf32_Rela *rela, Elf32_Addr base, Elf32_Sym *symtab,
struct module *me) struct module *me)
{ {
unsigned int i; struct mod_arch_syminfo *info;
ElfW(Rel) *rel = (void *)sechdrs[relsec].sh_addr; Elf32_Addr loc, val;
ElfW(Sym) *sym; int r_type, r_sym;
ElfW(Addr) *location;
DEBUGP("Applying relocate section %u to %u\n", relsec,
sechdrs[relsec].sh_info);
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
/* This is where to make the change */ /* This is where to make the change */
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr loc = base + rela->r_offset;
+ rel[i].r_offset;
/* This is the symbol it is referring to. Note that all /* This is the symbol it is referring to. Note that all
undefined symbols have been resolved. */ undefined symbols have been resolved. */
sym = (ElfW(Sym) *)sechdrs[symindex].sh_addr r_sym = ELF32_R_SYM(rela->r_info);
+ ELFW(R_SYM)(rel[i].r_info); r_type = ELF32_R_TYPE(rela->r_info);
info = me->arch.syminfo + r_sym;
val = symtab[r_sym].st_value;
switch (ELF_R_TYPE(rel[i].r_info)) { switch (r_type) {
case R_390_8: /* Direct 8 bit. */ case R_390_8: /* Direct 8 bit. */
*(u8*) location += sym->st_value;
break;
case R_390_12: /* Direct 12 bit. */ case R_390_12: /* Direct 12 bit. */
*(u16*) location = (*(u16*) location & 0xf000) |
(sym->st_value & 0xfff);
break;
case R_390_16: /* Direct 16 bit. */ case R_390_16: /* Direct 16 bit. */
*(u16*) location += sym->st_value;
break;
case R_390_32: /* Direct 32 bit. */ case R_390_32: /* Direct 32 bit. */
*(u32*) location += sym->st_value; val += rela->r_addend;
if (r_type == R_390_8)
*(unsigned char *) loc = val;
else if (r_type == R_390_12)
*(unsigned short *) loc = (val & 0xfff) |
(*(unsigned short *) loc & 0xf000);
else if (r_type == R_390_16)
*(unsigned short *) loc = val;
else if (r_type == R_390_32)
*(unsigned int *) loc = val;
break; break;
case R_390_PC16: /* PC relative 16 bit. */ case R_390_PC16: /* PC relative 16 bit. */
*(u16*) location += sym->st_value
- (unsigned long )location;
case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */ case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */
*(u16*) location += (sym->st_value case R_390_PC32DBL: /* PC relative 32 bit shifted by 1. */
- (unsigned long )location) >> 1;
case R_390_PC32: /* PC relative 32 bit. */ case R_390_PC32: /* PC relative 32 bit. */
*(u32*) location += sym->st_value val += rela->r_addend - loc;
- (unsigned long )location; if (r_type == R_390_PC16)
*(unsigned short *) loc = val;
else if (r_type == R_390_PC16DBL)
*(unsigned short *) loc = val >> 1;
else if (r_type == R_390_PC32DBL)
*(unsigned int *) loc = val >> 1;
else if (r_type == R_390_PC32)
*(unsigned int *) loc = val;
break; break;
case R_390_GOT12: /* 12 bit GOT offset. */ case R_390_GOT12: /* 12 bit GOT offset. */
case R_390_GOT16: /* 16 bit GOT offset. */ case R_390_GOT16: /* 16 bit GOT offset. */
case R_390_GOT32: /* 32 bit GOT offset. */ case R_390_GOT32: /* 32 bit GOT offset. */
// FIXME: TODO case R_390_GOTENT: /* 32 bit PC rel. to GOT entry shifted by 1. */
case R_390_GOTPLT12: /* 12 bit offset to jump slot. */
case R_390_GOTPLT16: /* 16 bit offset to jump slot. */
case R_390_GOTPLT32: /* 32 bit offset to jump slot. */
case R_390_GOTPLTENT: /* 32 bit rel. offset to jump slot >> 1. */
if (info->got_initialized == 0) {
Elf32_Addr *gotent;
gotent = me->module_core + me->arch.got_offset +
info->got_offset;
*gotent = val;
info->got_initialized = 1;
}
val = info->got_offset + rela->r_addend;
if (r_type == R_390_GOT12 ||
r_type == R_390_GOTPLT12)
*(unsigned short *) loc = (val & 0xfff) |
(*(unsigned short *) loc & 0xf000);
else if (r_type == R_390_GOT16 ||
r_type == R_390_GOTPLT16)
*(unsigned short *) loc = val;
else if (r_type == R_390_GOT32 ||
r_type == R_390_GOTPLT32)
*(unsigned int *) loc = val;
else if (r_type == R_390_GOTENT ||
r_type == R_390_GOTPLTENT)
*(unsigned int *) loc = val >> 1;
break; break;
case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */ case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */
case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */
case R_390_PLT32: /* 32 bit PC relative PLT address. */ case R_390_PLT32: /* 32 bit PC relative PLT address. */
// FIXME: TODO case R_390_PLTOFF16: /* 16 bit offset from GOT to PLT. */
case R_390_PLTOFF32: /* 32 bit offset from GOT to PLT. */
if (info->plt_initialized == 0) {
unsigned int *ip;
ip = me->module_core + me->arch.plt_offset +
info->plt_offset;
ip[0] = 0x0d105810; /* basr 1,0; l 1,6(1); br 1 */
ip[1] = 0x100607f1;
ip[2] = val;
info->plt_initialized = 1;
}
if (r_type == R_390_PLTOFF16 ||
r_type == R_390_PLTOFF32)
val = me->arch.plt_offset - me->arch.got_offset +
info->plt_offset + rela->r_addend;
else
val = (Elf32_Addr) me->module_core +
me->arch.plt_offset + info->plt_offset +
rela->r_addend - loc;
if (r_type == R_390_PLT16DBL)
*(unsigned short *) loc = val >> 1;
else if (r_type == R_390_PLTOFF16)
*(unsigned short *) loc = val;
else if (r_type == R_390_PLT32DBL)
*(unsigned int *) loc = val >> 1;
else if (r_type == R_390_PLT32 ||
r_type == R_390_PLTOFF32)
*(unsigned int *) loc = val;
break; break;
case R_390_GOTOFF16: /* 16 bit offset to GOT. */
case R_390_GOTOFF32: /* 32 bit offset to GOT. */
val = val + rela->r_addend -
((Elf32_Addr) me->module_core + me->arch.got_offset);
if (r_type == R_390_GOTOFF16)
*(unsigned short *) loc = val;
else if (r_type == R_390_GOTOFF32)
*(unsigned int *) loc = val;
break;
case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */
case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */
val = (Elf32_Addr) me->module_core + me->arch.got_offset +
rela->r_addend - loc;
if (r_type == R_390_GOTPC)
*(unsigned int *) loc = val;
else if (r_type == R_390_GOTPCDBL)
*(unsigned int *) loc = val >> 1;
break;
case R_390_COPY:
case R_390_GLOB_DAT: /* Create GOT entry. */ case R_390_GLOB_DAT: /* Create GOT entry. */
case R_390_JMP_SLOT: /* Create PLT entry. */ case R_390_JMP_SLOT: /* Create PLT entry. */
*location = sym->st_value;
break;
case R_390_RELATIVE: /* Adjust by program base. */ case R_390_RELATIVE: /* Adjust by program base. */
// FIXME: TODO /* Only needed if we want to support loading of
break; modules linked with -shared. */
case R_390_GOTOFF: /* 32 bit offset to GOT. */
// FIXME: TODO
break;
case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */
// FIXME: TODO
break; break;
default: default:
printk(KERN_ERR "module %s: Unknown relocation: %lu\n", printk(KERN_ERR "module %s: Unknown relocation: %u\n",
me->name, me->name, r_type);
(unsigned long)ELF_R_TYPE(rel[i].r_info));
return -ENOEXEC; return -ENOEXEC;
} }
}
return 0; return 0;
} }
int apply_relocate_add(Elf32_Shdr *sechdrs, int
const char *strtab, apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
unsigned int symindex, unsigned int symindex, unsigned int relsec,
unsigned int relsec,
struct module *me) struct module *me)
{ {
printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", Elf32_Addr base;
me->name); Elf32_Sym *symtab;
return -ENOEXEC; Elf32_Rela *rela;
unsigned long i, n;
int rc;
DEBUGP("Applying relocate section %u to %u\n",
relsec, sechdrs[relsec].sh_info);
base = sechdrs[sechdrs[relsec].sh_info].sh_addr;
symtab = (Elf32_Sym *) sechdrs[symindex].sh_addr;
rela = (Elf32_Rela *) sechdrs[relsec].sh_addr;
n = sechdrs[relsec].sh_size / sizeof(Elf32_Rela);
for (i = 0; i < n; i++, rela++) {
rc = apply_rela(rela, base, symtab, me);
if (rc)
return rc;
}
return 0;
} }
int module_finalize(const Elf_Ehdr *hdr, int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs, const Elf_Shdr *sechdrs,
struct module *me) struct module *me)
{ {
if (me->arch.syminfo)
kfree(me->arch.syminfo);
return 0; return 0;
} }
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
* arch/s390x/kernel/module.c - Kernel module help for s390x. * arch/s390x/kernel/module.c - Kernel module help for s390x.
* *
* S390 version * S390 version
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation * Copyright (C) 2002, 2003 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
* Author(s): Arnd Bergmann (arndb@de.ibm.com) * Author(s): Arnd Bergmann (arndb@de.ibm.com)
* Martin Schwidefsky (schwidefsky@de.ibm.com) * Martin Schwidefsky (schwidefsky@de.ibm.com)
* *
...@@ -36,6 +37,9 @@ ...@@ -36,6 +37,9 @@
#define DEBUGP(fmt , ...) #define DEBUGP(fmt , ...)
#endif #endif
#define GOT_ENTRY_SIZE 8
#define PLT_ENTRY_SIZE 20
void *module_alloc(unsigned long size) void *module_alloc(unsigned long size)
{ {
if (size == 0) if (size == 0)
...@@ -51,126 +55,322 @@ void module_free(struct module *mod, void *module_region) ...@@ -51,126 +55,322 @@ void module_free(struct module *mod, void *module_region)
table entries. */ table entries. */
} }
/* s390/s390x needs additional memory for GOT/PLT sections. */ static inline void
int module_frob_arch_sections(Elf_Ehdr *hdr, check_rela(Elf64_Rela *rela, struct module *me)
Elf_Shdr *sechdrs, {
char *secstrings, struct mod_arch_syminfo *info;
struct module *mod)
info = me->arch.syminfo + ELF64_R_SYM (rela->r_info);
switch (ELF64_R_TYPE (rela->r_info)) {
case R_390_GOT12: /* 12 bit GOT offset. */
case R_390_GOT16: /* 16 bit GOT offset. */
case R_390_GOT32: /* 32 bit GOT offset. */
case R_390_GOT64: /* 64 bit GOT offset. */
case R_390_GOTENT: /* 32 bit PC rel. to GOT entry shifted by 1. */
case R_390_GOTPLT12: /* 12 bit offset to jump slot. */
case R_390_GOTPLT16: /* 16 bit offset to jump slot. */
case R_390_GOTPLT32: /* 32 bit offset to jump slot. */
case R_390_GOTPLT64: /* 64 bit offset to jump slot. */
case R_390_GOTPLTENT: /* 32 bit rel. offset to jump slot >> 1. */
if (info->got_offset == -1UL) {
info->got_offset = me->arch.got_size;
me->arch.got_size += GOT_ENTRY_SIZE;
}
break;
case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */
case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */
case R_390_PLT32: /* 32 bit PC relative PLT address. */
case R_390_PLT64: /* 64 bit PC relative PLT address. */
case R_390_PLTOFF16: /* 16 bit offset from GOT to PLT. */
case R_390_PLTOFF32: /* 32 bit offset from GOT to PLT. */
case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */
if (info->plt_offset == -1UL) {
info->plt_offset = me->arch.plt_size;
me->arch.plt_size += PLT_ENTRY_SIZE;
}
break;
case R_390_COPY:
case R_390_GLOB_DAT:
case R_390_JMP_SLOT:
case R_390_RELATIVE:
/* Only needed if we want to support loading of
modules linked with -shared. */
break;
}
}
/*
* Account for GOT and PLT relocations. We can't add sections for
* got and plt but we can increase the core module size.
*/
int
module_frob_arch_sections(Elf64_Ehdr *hdr, Elf64_Shdr *sechdrs,
char *secstrings, struct module *me)
{ {
// FIXME: add space needed for GOT/PLT Elf64_Shdr *symtab;
Elf64_Sym *symbols;
Elf64_Rela *rela;
char *strings;
int nrela, i, j;
/* Find symbol table and string table. */
symtab = 0;
for (i = 0; i < hdr->e_shnum; i++)
switch (sechdrs[i].sh_type) {
case SHT_SYMTAB:
symtab = sechdrs + i;
break;
}
if (!symtab) {
printk(KERN_ERR "module %s: no symbol table\n", me->name);
return -ENOEXEC;
}
/* Allocate one syminfo structure per symbol. */
me->arch.nsyms = symtab->sh_size / sizeof(Elf64_Sym);
me->arch.syminfo = kmalloc(me->arch.nsyms *
sizeof(struct mod_arch_syminfo),
GFP_KERNEL);
if (!me->arch.syminfo)
return -ENOMEM;
symbols = (void *) hdr + symtab->sh_offset;
strings = (void *) hdr + sechdrs[symtab->sh_link].sh_offset;
for (i = 0; i < me->arch.nsyms; i++) {
if (symbols[i].st_shndx == SHN_UNDEF &&
strcmp(strings + symbols[i].st_name,
"_GLOBAL_OFFSET_TABLE_") == 0)
/* "Define" it as absolute. */
symbols[i].st_shndx = SHN_ABS;
me->arch.syminfo[i].got_offset = -1UL;
me->arch.syminfo[i].plt_offset = -1UL;
me->arch.syminfo[i].got_initialized = 0;
me->arch.syminfo[i].plt_initialized = 0;
}
/* Search for got/plt relocations. */
me->arch.got_size = me->arch.plt_size = 0;
for (i = 0; i < hdr->e_shnum; i++) {
if (sechdrs[i].sh_type != SHT_RELA)
continue;
nrela = sechdrs[i].sh_size / sizeof(Elf64_Rela);
rela = (void *) hdr + sechdrs[i].sh_offset;
for (j = 0; j < nrela; j++)
check_rela(rela + j, me);
}
/* Increase core size by size of got & plt and set start
offsets for got and plt. */
me->core_size = ALIGN(me->core_size, 4);
me->arch.got_offset = me->core_size;
me->core_size += me->arch.got_size;
me->arch.plt_offset = me->core_size;
me->core_size += me->arch.plt_size;
return 0; return 0;
} }
int apply_relocate(Elf_Shdr *sechdrs, int
const char *strtab, apply_relocate(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex,
unsigned int symindex, unsigned int relsec, struct module *me)
unsigned int relsec, {
printk(KERN_ERR "module %s: RELOCATION unsupported\n",
me->name);
return -ENOEXEC;
}
static inline int
apply_rela(Elf64_Rela *rela, Elf64_Addr base, Elf64_Sym *symtab,
struct module *me) struct module *me)
{ {
unsigned int i; struct mod_arch_syminfo *info;
ElfW(Rel) *rel = (void *)sechdrs[relsec].sh_addr; Elf64_Addr loc, val;
ElfW(Sym) *sym; int r_type, r_sym;
ElfW(Addr) *location;
DEBUGP("Applying relocate section %u to %u\n", relsec,
sechdrs[relsec].sh_info);
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
/* This is where to make the change */ /* This is where to make the change */
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr loc = base + rela->r_offset;
+ rel[i].r_offset;
/* This is the symbol it is referring to. Note that all /* This is the symbol it is referring to. Note that all
undefined symbols have been resolved. */ undefined symbols have been resolved. */
sym = (ElfW(Sym) *)sechdrs[symindex].sh_addr r_sym = ELF64_R_SYM(rela->r_info);
+ ELFW(R_SYM)(rel[i].r_info); r_type = ELF64_R_TYPE(rela->r_info);
info = me->arch.syminfo + r_sym;
val = symtab[r_sym].st_value;
switch (ELF_R_TYPE(rel[i].r_info)) { switch (r_type) {
case R_390_8: /* Direct 8 bit. */ case R_390_8: /* Direct 8 bit. */
*(u8*) location += sym->st_value;
break;
case R_390_12: /* Direct 12 bit. */ case R_390_12: /* Direct 12 bit. */
*(u16*) location = (*(u16*) location & 0xf000) |
(sym->st_value & 0xfff);
break;
case R_390_16: /* Direct 16 bit. */ case R_390_16: /* Direct 16 bit. */
*(u16*) location += sym->st_value;
break;
case R_390_32: /* Direct 32 bit. */ case R_390_32: /* Direct 32 bit. */
*(u32*) location += sym->st_value;
break;
case R_390_64: /* Direct 64 bit. */ case R_390_64: /* Direct 64 bit. */
*(u64*) location += sym->st_value; val += rela->r_addend;
if (r_type == R_390_8)
*(unsigned char *) loc = val;
else if (r_type == R_390_12)
*(unsigned short *) loc = (val & 0xfff) |
(*(unsigned short *) loc & 0xf000);
else if (r_type == R_390_16)
*(unsigned short *) loc = val;
else if (r_type == R_390_32)
*(unsigned int *) loc = val;
else if (r_type == R_390_64)
*(unsigned long *) loc = val;
break; break;
case R_390_PC16: /* PC relative 16 bit. */ case R_390_PC16: /* PC relative 16 bit. */
*(u16*) location += sym->st_value
- (unsigned long )location;
case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */ case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */
*(u16*) location += (sym->st_value
- (unsigned long )location) >> 1;
case R_390_PC32: /* PC relative 32 bit. */
*(u32*) location += sym->st_value
- (unsigned long )location;
break;
case R_390_PC32DBL: /* PC relative 32 bit shifted by 1. */ case R_390_PC32DBL: /* PC relative 32 bit shifted by 1. */
*(u32*) location += (sym->st_value case R_390_PC32: /* PC relative 32 bit. */
- (unsigned long )location) >> 1;
break;
case R_390_PC64: /* PC relative 64 bit. */ case R_390_PC64: /* PC relative 64 bit. */
*(u64*) location += sym->st_value val += rela->r_addend - loc;
- (unsigned long )location; if (r_type == R_390_PC16)
*(unsigned short *) loc = val;
else if (r_type == R_390_PC16DBL)
*(unsigned short *) loc = val >> 1;
else if (r_type == R_390_PC32DBL)
*(unsigned int *) loc = val >> 1;
else if (r_type == R_390_PC32)
*(unsigned int *) loc = val;
else if (r_type == R_390_PC64)
*(unsigned long *) loc = val;
break; break;
case R_390_GOT12: /* 12 bit GOT offset. */ case R_390_GOT12: /* 12 bit GOT offset. */
case R_390_GOT16: /* 16 bit GOT offset. */ case R_390_GOT16: /* 16 bit GOT offset. */
case R_390_GOT32: /* 32 bit GOT offset. */ case R_390_GOT32: /* 32 bit GOT offset. */
case R_390_GOT64: /* 64 bit GOT offset. */ case R_390_GOT64: /* 64 bit GOT offset. */
case R_390_GOTENT: /* 32 bit PC rel. to GOT entry >> 1. */ case R_390_GOTENT: /* 32 bit PC rel. to GOT entry shifted by 1. */
// FIXME: TODO case R_390_GOTPLT12: /* 12 bit offset to jump slot. */
case R_390_GOTPLT16: /* 16 bit offset to jump slot. */
case R_390_GOTPLT32: /* 32 bit offset to jump slot. */
case R_390_GOTPLT64: /* 64 bit offset to jump slot. */
case R_390_GOTPLTENT: /* 32 bit rel. offset to jump slot >> 1. */
if (info->got_initialized == 0) {
Elf64_Addr *gotent;
gotent = me->module_core + me->arch.got_offset +
info->got_offset;
*gotent = val;
info->got_initialized = 1;
}
val = info->got_offset + rela->r_addend;
if (r_type == R_390_GOT12 ||
r_type == R_390_GOTPLT12)
*(unsigned short *) loc = (val & 0xfff) |
(*(unsigned short *) loc & 0xf000);
else if (r_type == R_390_GOT16 ||
r_type == R_390_GOTPLT16)
*(unsigned short *) loc = val;
else if (r_type == R_390_GOT32 ||
r_type == R_390_GOTPLT32)
*(unsigned int *) loc = val;
else if (r_type == R_390_GOTENT ||
r_type == R_390_GOTPLTENT)
*(unsigned int *) loc = val >> 1;
else if (r_type == R_390_GOT64 ||
r_type == R_390_GOTPLT64)
*(unsigned long *) loc = val;
break; break;
case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */ case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */
case R_390_PLT32: /* 32 bit PC relative PLT address. */
case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */ case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */
case R_390_PLT32: /* 32 bit PC relative PLT address. */
case R_390_PLT64: /* 64 bit PC relative PLT address. */ case R_390_PLT64: /* 64 bit PC relative PLT address. */
// FIXME: TODO case R_390_PLTOFF16: /* 16 bit offset from GOT to PLT. */
case R_390_PLTOFF32: /* 32 bit offset from GOT to PLT. */
case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */
if (info->plt_initialized == 0) {
unsigned int *ip;
ip = me->module_core + me->arch.plt_offset +
info->plt_offset;
ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */
ip[1] = 0x100a0004;
ip[2] = 0x07f10000;
ip[3] = (unsigned int) (val >> 32);
ip[4] = (unsigned int) val;
info->plt_initialized = 1;
}
if (r_type == R_390_PLTOFF16 ||
r_type == R_390_PLTOFF32 ||
r_type == R_390_PLTOFF64)
val = me->arch.plt_offset - me->arch.got_offset +
info->plt_offset + rela->r_addend;
else
val = (Elf64_Addr) me->module_core +
me->arch.plt_offset + info->plt_offset +
rela->r_addend - loc;
if (r_type == R_390_PLT16DBL)
*(unsigned short *) loc = val >> 1;
else if (r_type == R_390_PLTOFF16)
*(unsigned short *) loc = val;
else if (r_type == R_390_PLT32DBL)
*(unsigned int *) loc = val >> 1;
else if (r_type == R_390_PLT32 ||
r_type == R_390_PLTOFF32)
*(unsigned int *) loc = val;
else if (r_type == R_390_PLT64 ||
r_type == R_390_PLTOFF64)
*(unsigned long *) loc = val;
break;
case R_390_GOTOFF16: /* 16 bit offset to GOT. */
case R_390_GOTOFF32: /* 32 bit offset to GOT. */
case R_390_GOTOFF64: /* 64 bit offset to GOT. */
val = val + rela->r_addend -
((Elf64_Addr) me->module_core + me->arch.got_offset);
if (r_type == R_390_GOTOFF16)
*(unsigned short *) loc = val;
else if (r_type == R_390_GOTOFF32)
*(unsigned int *) loc = val;
else if (r_type == R_390_GOTOFF64)
*(unsigned long *) loc = val;
break; break;
case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */
case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */
val = (Elf64_Addr) me->module_core + me->arch.got_offset +
rela->r_addend - loc;
if (r_type == R_390_GOTPC)
*(unsigned int *) loc = val;
else if (r_type == R_390_GOTPCDBL)
*(unsigned int *) loc = val >> 1;
break;
case R_390_COPY:
case R_390_GLOB_DAT: /* Create GOT entry. */ case R_390_GLOB_DAT: /* Create GOT entry. */
case R_390_JMP_SLOT: /* Create PLT entry. */ case R_390_JMP_SLOT: /* Create PLT entry. */
*location = sym->st_value;
break;
case R_390_RELATIVE: /* Adjust by program base. */ case R_390_RELATIVE: /* Adjust by program base. */
// FIXME: TODO /* Only needed if we want to support loading of
break; modules linked with -shared. */
case R_390_GOTOFF: /* 32 bit offset to GOT. */
// FIXME: TODO
break;
case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */
case R_390_GOTPCDBL: /* 32 bit PC rel. GOT shifted by 1. */
// FIXME: TODO
break; break;
default: default:
printk(KERN_ERR "module %s: Unknown relocation: %lu\n", printk(KERN_ERR "module %s: Unknown relocation: %u\n",
me->name, me->name, r_type);
(unsigned long)ELF_R_TYPE(rel[i].r_info));
return -ENOEXEC; return -ENOEXEC;
} }
}
return 0; return 0;
} }
int apply_relocate_add(Elf32_Shdr *sechdrs, int
const char *strtab, apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab,
unsigned int symindex, unsigned int symindex, unsigned int relsec,
unsigned int relsec,
struct module *me) struct module *me)
{ {
printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", Elf64_Addr base;
me->name); Elf64_Sym *symtab;
return -ENOEXEC; Elf64_Rela *rela;
unsigned long i, n;
int rc;
DEBUGP("Applying relocate section %u to %u\n",
relsec, sechdrs[relsec].sh_info);
base = sechdrs[sechdrs[relsec].sh_info].sh_addr;
symtab = (Elf64_Sym *) sechdrs[symindex].sh_addr;
rela = (Elf64_Rela *) sechdrs[relsec].sh_addr;
n = sechdrs[relsec].sh_size / sizeof(Elf64_Rela);
for (i = 0; i < n; i++, rela++) {
rc = apply_rela(rela, base, symtab, me);
if (rc)
return rc;
}
return 0;
} }
int module_finalize(const Elf_Ehdr *hdr, int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs, const Elf_Shdr *sechdrs,
struct module *me) struct module *me)
{ {
if (me->arch.syminfo)
kfree(me->arch.syminfo);
return 0; return 0;
} }
...@@ -4,10 +4,28 @@ ...@@ -4,10 +4,28 @@
* This file contains the s390 architecture specific module code. * This file contains the s390 architecture specific module code.
*/ */
struct mod_arch_syminfo
{
unsigned long got_offset;
unsigned long plt_offset;
int got_initialized;
int plt_initialized;
};
struct mod_arch_specific struct mod_arch_specific
{ {
void *module_got, *module_plt; /* Starting offset of got in the module core memory. */
unsigned long got_size, plt_size; unsigned long got_offset;
/* Starting offset of plt in the module core memory. */
unsigned long plt_offset;
/* Size of the got. */
unsigned long got_size;
/* Size of the plt. */
unsigned long plt_size;
/* Number of symbols in syminfo. */
int nsyms;
/* Additional symbol information (got and plt offsets). */
struct mod_arch_syminfo *syminfo;
}; };
#ifdef CONFIG_ARCH_S390X #ifdef CONFIG_ARCH_S390X
......
...@@ -4,10 +4,28 @@ ...@@ -4,10 +4,28 @@
* This file contains the s390 architecture specific module code. * This file contains the s390 architecture specific module code.
*/ */
struct mod_arch_syminfo
{
unsigned long got_offset;
unsigned long plt_offset;
int got_initialized;
int plt_initialized;
};
struct mod_arch_specific struct mod_arch_specific
{ {
void *module_got, *module_plt; /* Starting offset of got in the module core memory. */
unsigned long got_size, plt_size; unsigned long got_offset;
/* Starting offset of plt in the module core memory. */
unsigned long plt_offset;
/* Size of the got. */
unsigned long got_size;
/* Size of the plt. */
unsigned long plt_size;
/* Number of symbols in syminfo. */
int nsyms;
/* Additional symbol information (got and plt offsets). */
struct mod_arch_syminfo *syminfo;
}; };
#ifdef CONFIG_ARCH_S390X #ifdef CONFIG_ARCH_S390X
......
...@@ -446,8 +446,8 @@ typedef struct { ...@@ -446,8 +446,8 @@ typedef struct {
#define R_390_GLOB_DAT 10 /* Create GOT entry. */ #define R_390_GLOB_DAT 10 /* Create GOT entry. */
#define R_390_JMP_SLOT 11 /* Create PLT entry. */ #define R_390_JMP_SLOT 11 /* Create PLT entry. */
#define R_390_RELATIVE 12 /* Adjust by program base. */ #define R_390_RELATIVE 12 /* Adjust by program base. */
#define R_390_GOTOFF 13 /* 32 bit offset to GOT. */ #define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */
#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ #define R_390_GOTPC 14 /* 32 bit PC rel. offset to GOT. */
#define R_390_GOT16 15 /* 16 bit GOT offset. */ #define R_390_GOT16 15 /* 16 bit GOT offset. */
#define R_390_PC16 16 /* PC relative 16 bit. */ #define R_390_PC16 16 /* PC relative 16 bit. */
#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ #define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */
...@@ -460,8 +460,55 @@ typedef struct { ...@@ -460,8 +460,55 @@ typedef struct {
#define R_390_GOT64 24 /* 64 bit GOT offset. */ #define R_390_GOT64 24 /* 64 bit GOT offset. */
#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ #define R_390_PLT64 25 /* 64 bit PC relative PLT address. */
#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ #define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */
#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */
#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */
#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */
#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */
#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */
#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */
#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */
#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */
#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */
#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */
#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */
#define R_390_TLS_GDCALL 38 /* Tag for function call in general
dynamic TLS code. */
#define R_390_TLS_LDCALL 39 /* Tag for function call in local
dynamic TLS code. */
#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic
thread local data. */
#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic
thread local data. */
#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS
block offset. */
#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS
block offset. */
#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS
block offset. */
#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic
thread local data in LD code. */
#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic
thread local data in LD code. */
#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for
negated static TLS block offset. */
#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for
negated static TLS block offset. */
#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for
negated static TLS block offset. */
#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to
static TLS block. */
#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to
static TLS block. */
#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS
block. */
#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS
block. */
#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */
#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */
#define R_390_TLS_TPOFF 56 /* Negate offset in static TLS
block. */
/* Keep this the last entry. */ /* Keep this the last entry. */
#define R_390_NUM 27 #define R_390_NUM 57
/* x86-64 relocation types */ /* x86-64 relocation types */
#define R_X86_64_NONE 0 /* No reloc */ #define R_X86_64_NONE 0 /* No reloc */
...@@ -484,37 +531,6 @@ typedef struct { ...@@ -484,37 +531,6 @@ typedef struct {
#define R_X86_64_NUM 16 #define R_X86_64_NUM 16
/* s390 relocations defined by the ABIs */
#define R_390_NONE 0 /* No reloc. */
#define R_390_8 1 /* Direct 8 bit. */
#define R_390_12 2 /* Direct 12 bit. */
#define R_390_16 3 /* Direct 16 bit. */
#define R_390_32 4 /* Direct 32 bit. */
#define R_390_PC32 5 /* PC relative 32 bit. */
#define R_390_GOT12 6 /* 12 bit GOT offset. */
#define R_390_GOT32 7 /* 32 bit GOT offset. */
#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */
#define R_390_COPY 9 /* Copy symbol at runtime. */
#define R_390_GLOB_DAT 10 /* Create GOT entry. */
#define R_390_JMP_SLOT 11 /* Create PLT entry. */
#define R_390_RELATIVE 12 /* Adjust by program base. */
#define R_390_GOTOFF 13 /* 32 bit offset to GOT. */
#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */
#define R_390_GOT16 15 /* 16 bit GOT offset. */
#define R_390_PC16 16 /* PC relative 16 bit. */
#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */
#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */
#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */
#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */
#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */
#define R_390_64 22 /* Direct 64 bit. */
#define R_390_PC64 23 /* PC relative 64 bit. */
#define R_390_GOT64 24 /* 64 bit GOT offset. */
#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */
#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */
/* Keep this the last entry. */
#define R_390_NUM 27
/* Legal values for e_flags field of Elf64_Ehdr. */ /* Legal values for e_flags field of Elf64_Ehdr. */
#define EF_ALPHA_32BIT 1 /* All addresses are below 2GB */ #define EF_ALPHA_32BIT 1 /* All addresses are below 2GB */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment