diff options
Diffstat (limited to 'arch/mn10300/kernel/module.c')
| -rw-r--r-- | arch/mn10300/kernel/module.c | 41 | 
1 files changed, 36 insertions, 5 deletions
diff --git a/arch/mn10300/kernel/module.c b/arch/mn10300/kernel/module.c index 6b287f2e8e8..6aea7fd7699 100644 --- a/arch/mn10300/kernel/module.c +++ b/arch/mn10300/kernel/module.c @@ -1,6 +1,6 @@  /* 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   * @@ -48,8 +48,6 @@ void *module_alloc(unsigned long size)  void module_free(struct module *mod, void *module_region)  {  	vfree(module_region); -	/* FIXME: If module_region == mod->init_region, trim exception -	 * table entries. */  }  /* @@ -105,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; @@ -128,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 */ @@ -159,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;  }  |