Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5ae8606d authored by Mark Salter's avatar Mark Salter Committed by Linus Torvalds
Browse files

MN10300: Add support for new ELF relocs in kernel modules



Add support for new relocs which may show up in MN10300 kernel modules due to
linker relaxation.

Signed-off-by: default avatarMark Salter <msalter@redhat.com>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent d2829224
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@
#define R_MN10300_PCREL8	6	/* PC-relative 8-bit signed.  */
#define R_MN10300_24		9	/* Direct 24 bit.  */
#define R_MN10300_RELATIVE	23	/* Adjust by program base.  */
#define R_MN10300_SYM_DIFF	33	/* Adjustment when relaxing. */
#define R_MN10300_ALIGN 	34	/* Alignment requirement. */

/*
 * ELF register definitions..
+36 −3
Original line number Diff line number Diff line
/* MN10300 Kernel module helper routines
 *
 * Copyright (C) 2007, 2008 Red Hat, Inc. All Rights Reserved.
 * Copyright (C) 2007, 2008, 2009 Red Hat, Inc. All Rights Reserved.
 * Written by Mark Salter (msalter@redhat.com)
 * - Derived from arch/i386/kernel/module.c
 *
@@ -103,10 +103,10 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
		       unsigned int relsec,
		       struct module *me)
{
	unsigned int i;
	unsigned int i, sym_diff_seen = 0;
	Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
	Elf32_Sym *sym;
	Elf32_Addr relocation;
	Elf32_Addr relocation, sym_diff_val = 0;
	uint8_t *location;
	uint32_t value;

@@ -126,6 +126,22 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
		/* this is the adjustment to be made */
		relocation = sym->st_value + rel[i].r_addend;

		if (sym_diff_seen) {
			switch (ELF32_R_TYPE(rel[i].r_info)) {
			case R_MN10300_32:
			case R_MN10300_24:
			case R_MN10300_16:
			case R_MN10300_8:
				relocation -= sym_diff_val;
				sym_diff_seen = 0;
				break;
			default:
				printk(KERN_ERR "module %s: Unexpected SYM_DIFF relocation: %u\n",
				       me->name, ELF32_R_TYPE(rel[i].r_info));
				return -ENOEXEC;
			}
		}

		switch (ELF32_R_TYPE(rel[i].r_info)) {
			/* for the first four relocation types, we simply
			 * store the adjustment at the location given */
@@ -157,12 +173,29 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
			*location = relocation - (uint32_t) location;
			break;

		case R_MN10300_SYM_DIFF:
			/* This is used to adjust the next reloc as required
			 * by relaxation. */
			sym_diff_seen = 1;
			sym_diff_val = sym->st_value;
			break;

		case R_MN10300_ALIGN:
			/* Just ignore the ALIGN relocs.
			 * Only interesting if kernel performed relaxation. */
			continue;

		default:
			printk(KERN_ERR "module %s: Unknown relocation: %u\n",
			       me->name, ELF32_R_TYPE(rel[i].r_info));
			return -ENOEXEC;
		}
	}
	if (sym_diff_seen) {
		printk(KERN_ERR "module %s: Nothing follows SYM_DIFF relocation: %u\n",
				       me->name, ELF32_R_TYPE(rel[i].r_info));
		return -ENOEXEC;
	}
	return 0;
}