162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * OpenRISC module.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Linux architectural port borrowing liberally from similar works of 662306a36Sopenharmony_ci * others. All original copyrights apply as per the original source 762306a36Sopenharmony_ci * declaration. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Modifications for the OpenRISC architecture: 1062306a36Sopenharmony_ci * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/moduleloader.h> 1462306a36Sopenharmony_ci#include <linux/elf.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ciint apply_relocate_add(Elf32_Shdr *sechdrs, 1762306a36Sopenharmony_ci const char *strtab, 1862306a36Sopenharmony_ci unsigned int symindex, 1962306a36Sopenharmony_ci unsigned int relsec, 2062306a36Sopenharmony_ci struct module *me) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci unsigned int i; 2362306a36Sopenharmony_ci Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; 2462306a36Sopenharmony_ci Elf32_Sym *sym; 2562306a36Sopenharmony_ci uint32_t *location; 2662306a36Sopenharmony_ci uint32_t value; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci pr_debug("Applying relocate section %u to %u\n", relsec, 2962306a36Sopenharmony_ci sechdrs[relsec].sh_info); 3062306a36Sopenharmony_ci for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 3162306a36Sopenharmony_ci /* This is where to make the change */ 3262306a36Sopenharmony_ci location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 3362306a36Sopenharmony_ci + rel[i].r_offset; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci /* This is the symbol it is referring to. Note that all 3662306a36Sopenharmony_ci undefined symbols have been resolved. */ 3762306a36Sopenharmony_ci sym = (Elf32_Sym *)sechdrs[symindex].sh_addr 3862306a36Sopenharmony_ci + ELF32_R_SYM(rel[i].r_info); 3962306a36Sopenharmony_ci value = sym->st_value + rel[i].r_addend; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci switch (ELF32_R_TYPE(rel[i].r_info)) { 4262306a36Sopenharmony_ci case R_OR32_32: 4362306a36Sopenharmony_ci *location = value; 4462306a36Sopenharmony_ci break; 4562306a36Sopenharmony_ci case R_OR32_CONST: 4662306a36Sopenharmony_ci *((uint16_t *)location + 1) = value; 4762306a36Sopenharmony_ci break; 4862306a36Sopenharmony_ci case R_OR32_CONSTH: 4962306a36Sopenharmony_ci *((uint16_t *)location + 1) = value >> 16; 5062306a36Sopenharmony_ci break; 5162306a36Sopenharmony_ci case R_OR32_JUMPTARG: 5262306a36Sopenharmony_ci value -= (uint32_t)location; 5362306a36Sopenharmony_ci value >>= 2; 5462306a36Sopenharmony_ci value &= 0x03ffffff; 5562306a36Sopenharmony_ci value |= *location & 0xfc000000; 5662306a36Sopenharmony_ci *location = value; 5762306a36Sopenharmony_ci break; 5862306a36Sopenharmony_ci default: 5962306a36Sopenharmony_ci pr_err("module %s: Unknown relocation: %u\n", 6062306a36Sopenharmony_ci me->name, ELF32_R_TYPE(rel[i].r_info)); 6162306a36Sopenharmony_ci break; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci return 0; 6662306a36Sopenharmony_ci} 67