1fd045f6cSArd Biesheuvel /* 224af6c4eSArd Biesheuvel * Copyright (C) 2014-2017 Linaro Ltd. <ard.biesheuvel@linaro.org> 3fd045f6cSArd Biesheuvel * 4fd045f6cSArd Biesheuvel * This program is free software; you can redistribute it and/or modify 5fd045f6cSArd Biesheuvel * it under the terms of the GNU General Public License version 2 as 6fd045f6cSArd Biesheuvel * published by the Free Software Foundation. 7fd045f6cSArd Biesheuvel */ 8fd045f6cSArd Biesheuvel 9fd045f6cSArd Biesheuvel #include <linux/elf.h> 10fd045f6cSArd Biesheuvel #include <linux/kernel.h> 11fd045f6cSArd Biesheuvel #include <linux/module.h> 12fd045f6cSArd Biesheuvel #include <linux/sort.h> 13fd045f6cSArd Biesheuvel 1424af6c4eSArd Biesheuvel static bool in_init(const struct module *mod, void *loc) 15fd045f6cSArd Biesheuvel { 1624af6c4eSArd Biesheuvel return (u64)loc - (u64)mod->init_layout.base < mod->init_layout.size; 17fd045f6cSArd Biesheuvel } 18fd045f6cSArd Biesheuvel 1924af6c4eSArd Biesheuvel u64 module_emit_plt_entry(struct module *mod, void *loc, const Elf64_Rela *rela, 2024af6c4eSArd Biesheuvel Elf64_Sym *sym) 2124af6c4eSArd Biesheuvel { 2224af6c4eSArd Biesheuvel struct mod_plt_sec *pltsec = !in_init(mod, loc) ? &mod->arch.core : 2324af6c4eSArd Biesheuvel &mod->arch.init; 2424af6c4eSArd Biesheuvel struct plt_entry *plt = (struct plt_entry *)pltsec->plt->sh_addr; 2524af6c4eSArd Biesheuvel int i = pltsec->plt_num_entries; 2624af6c4eSArd Biesheuvel u64 val = sym->st_value + rela->r_addend; 27fd045f6cSArd Biesheuvel 287e8b9c1dSArd Biesheuvel plt[i] = get_plt_entry(val); 29fd045f6cSArd Biesheuvel 3024af6c4eSArd Biesheuvel /* 3124af6c4eSArd Biesheuvel * Check if the entry we just created is a duplicate. Given that the 3224af6c4eSArd Biesheuvel * relocations are sorted, this will be the last entry we allocated. 3324af6c4eSArd Biesheuvel * (if one exists). 3424af6c4eSArd Biesheuvel */ 357e8b9c1dSArd Biesheuvel if (i > 0 && plt_entries_equal(plt + i, plt + i - 1)) 3624af6c4eSArd Biesheuvel return (u64)&plt[i - 1]; 3724af6c4eSArd Biesheuvel 3824af6c4eSArd Biesheuvel pltsec->plt_num_entries++; 3924af6c4eSArd Biesheuvel BUG_ON(pltsec->plt_num_entries > pltsec->plt_max_entries); 40fd045f6cSArd Biesheuvel 41fd045f6cSArd Biesheuvel return (u64)&plt[i]; 42fd045f6cSArd Biesheuvel } 43fd045f6cSArd Biesheuvel 44fd045f6cSArd Biesheuvel #define cmp_3way(a,b) ((a) < (b) ? -1 : (a) > (b)) 45fd045f6cSArd Biesheuvel 46fd045f6cSArd Biesheuvel static int cmp_rela(const void *a, const void *b) 47fd045f6cSArd Biesheuvel { 48fd045f6cSArd Biesheuvel const Elf64_Rela *x = a, *y = b; 49fd045f6cSArd Biesheuvel int i; 50fd045f6cSArd Biesheuvel 51fd045f6cSArd Biesheuvel /* sort by type, symbol index and addend */ 52fd045f6cSArd Biesheuvel i = cmp_3way(ELF64_R_TYPE(x->r_info), ELF64_R_TYPE(y->r_info)); 53fd045f6cSArd Biesheuvel if (i == 0) 54fd045f6cSArd Biesheuvel i = cmp_3way(ELF64_R_SYM(x->r_info), ELF64_R_SYM(y->r_info)); 55fd045f6cSArd Biesheuvel if (i == 0) 56fd045f6cSArd Biesheuvel i = cmp_3way(x->r_addend, y->r_addend); 57fd045f6cSArd Biesheuvel return i; 58fd045f6cSArd Biesheuvel } 59fd045f6cSArd Biesheuvel 60fd045f6cSArd Biesheuvel static bool duplicate_rel(const Elf64_Rela *rela, int num) 61fd045f6cSArd Biesheuvel { 62fd045f6cSArd Biesheuvel /* 63fd045f6cSArd Biesheuvel * Entries are sorted by type, symbol index and addend. That means 64fd045f6cSArd Biesheuvel * that, if a duplicate entry exists, it must be in the preceding 65fd045f6cSArd Biesheuvel * slot. 66fd045f6cSArd Biesheuvel */ 67fd045f6cSArd Biesheuvel return num > 0 && cmp_rela(rela + num, rela + num - 1) == 0; 68fd045f6cSArd Biesheuvel } 69fd045f6cSArd Biesheuvel 7024af6c4eSArd Biesheuvel static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num, 7124af6c4eSArd Biesheuvel Elf64_Word dstidx) 72fd045f6cSArd Biesheuvel { 73fd045f6cSArd Biesheuvel unsigned int ret = 0; 74fd045f6cSArd Biesheuvel Elf64_Sym *s; 75fd045f6cSArd Biesheuvel int i; 76fd045f6cSArd Biesheuvel 77fd045f6cSArd Biesheuvel for (i = 0; i < num; i++) { 78fd045f6cSArd Biesheuvel switch (ELF64_R_TYPE(rela[i].r_info)) { 79fd045f6cSArd Biesheuvel case R_AARCH64_JUMP26: 80fd045f6cSArd Biesheuvel case R_AARCH64_CALL26: 81fd045f6cSArd Biesheuvel /* 82fd045f6cSArd Biesheuvel * We only have to consider branch targets that resolve 8324af6c4eSArd Biesheuvel * to symbols that are defined in a different section. 8424af6c4eSArd Biesheuvel * This is not simply a heuristic, it is a fundamental 8524af6c4eSArd Biesheuvel * limitation, since there is no guaranteed way to emit 8624af6c4eSArd Biesheuvel * PLT entries sufficiently close to the branch if the 8724af6c4eSArd Biesheuvel * section size exceeds the range of a branch 8824af6c4eSArd Biesheuvel * instruction. So ignore relocations against defined 8924af6c4eSArd Biesheuvel * symbols if they live in the same section as the 9024af6c4eSArd Biesheuvel * relocation target. 91fd045f6cSArd Biesheuvel */ 92fd045f6cSArd Biesheuvel s = syms + ELF64_R_SYM(rela[i].r_info); 9324af6c4eSArd Biesheuvel if (s->st_shndx == dstidx) 94fd045f6cSArd Biesheuvel break; 95fd045f6cSArd Biesheuvel 96fd045f6cSArd Biesheuvel /* 97fd045f6cSArd Biesheuvel * Jump relocations with non-zero addends against 98fd045f6cSArd Biesheuvel * undefined symbols are supported by the ELF spec, but 99fd045f6cSArd Biesheuvel * do not occur in practice (e.g., 'jump n bytes past 100fd045f6cSArd Biesheuvel * the entry point of undefined function symbol f'). 101fd045f6cSArd Biesheuvel * So we need to support them, but there is no need to 102fd045f6cSArd Biesheuvel * take them into consideration when trying to optimize 103fd045f6cSArd Biesheuvel * this code. So let's only check for duplicates when 104fd045f6cSArd Biesheuvel * the addend is zero: this allows us to record the PLT 105fd045f6cSArd Biesheuvel * entry address in the symbol table itself, rather than 106fd045f6cSArd Biesheuvel * having to search the list for duplicates each time we 107fd045f6cSArd Biesheuvel * emit one. 108fd045f6cSArd Biesheuvel */ 109fd045f6cSArd Biesheuvel if (rela[i].r_addend != 0 || !duplicate_rel(rela, i)) 110fd045f6cSArd Biesheuvel ret++; 111fd045f6cSArd Biesheuvel break; 112fd045f6cSArd Biesheuvel } 113fd045f6cSArd Biesheuvel } 114fd045f6cSArd Biesheuvel return ret; 115fd045f6cSArd Biesheuvel } 116fd045f6cSArd Biesheuvel 117fd045f6cSArd Biesheuvel int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, 118fd045f6cSArd Biesheuvel char *secstrings, struct module *mod) 119fd045f6cSArd Biesheuvel { 12024af6c4eSArd Biesheuvel unsigned long core_plts = 0; 12124af6c4eSArd Biesheuvel unsigned long init_plts = 0; 122fd045f6cSArd Biesheuvel Elf64_Sym *syms = NULL; 123fd045f6cSArd Biesheuvel int i; 124fd045f6cSArd Biesheuvel 125fd045f6cSArd Biesheuvel /* 126fd045f6cSArd Biesheuvel * Find the empty .plt section so we can expand it to store the PLT 127fd045f6cSArd Biesheuvel * entries. Record the symtab address as well. 128fd045f6cSArd Biesheuvel */ 129fd045f6cSArd Biesheuvel for (i = 0; i < ehdr->e_shnum; i++) { 13024af6c4eSArd Biesheuvel if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt")) 13124af6c4eSArd Biesheuvel mod->arch.core.plt = sechdrs + i; 13224af6c4eSArd Biesheuvel else if (!strcmp(secstrings + sechdrs[i].sh_name, ".init.plt")) 13324af6c4eSArd Biesheuvel mod->arch.init.plt = sechdrs + i; 134fd045f6cSArd Biesheuvel else if (sechdrs[i].sh_type == SHT_SYMTAB) 135fd045f6cSArd Biesheuvel syms = (Elf64_Sym *)sechdrs[i].sh_addr; 136fd045f6cSArd Biesheuvel } 137fd045f6cSArd Biesheuvel 13824af6c4eSArd Biesheuvel if (!mod->arch.core.plt || !mod->arch.init.plt) { 13924af6c4eSArd Biesheuvel pr_err("%s: module PLT section(s) missing\n", mod->name); 140fd045f6cSArd Biesheuvel return -ENOEXEC; 141fd045f6cSArd Biesheuvel } 142fd045f6cSArd Biesheuvel if (!syms) { 143fd045f6cSArd Biesheuvel pr_err("%s: module symtab section missing\n", mod->name); 144fd045f6cSArd Biesheuvel return -ENOEXEC; 145fd045f6cSArd Biesheuvel } 146fd045f6cSArd Biesheuvel 147fd045f6cSArd Biesheuvel for (i = 0; i < ehdr->e_shnum; i++) { 148fd045f6cSArd Biesheuvel Elf64_Rela *rels = (void *)ehdr + sechdrs[i].sh_offset; 149fd045f6cSArd Biesheuvel int numrels = sechdrs[i].sh_size / sizeof(Elf64_Rela); 150fd045f6cSArd Biesheuvel Elf64_Shdr *dstsec = sechdrs + sechdrs[i].sh_info; 151fd045f6cSArd Biesheuvel 152fd045f6cSArd Biesheuvel if (sechdrs[i].sh_type != SHT_RELA) 153fd045f6cSArd Biesheuvel continue; 154fd045f6cSArd Biesheuvel 155fd045f6cSArd Biesheuvel /* ignore relocations that operate on non-exec sections */ 156fd045f6cSArd Biesheuvel if (!(dstsec->sh_flags & SHF_EXECINSTR)) 157fd045f6cSArd Biesheuvel continue; 158fd045f6cSArd Biesheuvel 159fd045f6cSArd Biesheuvel /* sort by type, symbol index and addend */ 160fd045f6cSArd Biesheuvel sort(rels, numrels, sizeof(Elf64_Rela), cmp_rela, NULL); 161fd045f6cSArd Biesheuvel 16224af6c4eSArd Biesheuvel if (strncmp(secstrings + dstsec->sh_name, ".init", 5) != 0) 16324af6c4eSArd Biesheuvel core_plts += count_plts(syms, rels, numrels, 16424af6c4eSArd Biesheuvel sechdrs[i].sh_info); 16524af6c4eSArd Biesheuvel else 16624af6c4eSArd Biesheuvel init_plts += count_plts(syms, rels, numrels, 16724af6c4eSArd Biesheuvel sechdrs[i].sh_info); 168fd045f6cSArd Biesheuvel } 169fd045f6cSArd Biesheuvel 17024af6c4eSArd Biesheuvel mod->arch.core.plt->sh_type = SHT_NOBITS; 17124af6c4eSArd Biesheuvel mod->arch.core.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; 17224af6c4eSArd Biesheuvel mod->arch.core.plt->sh_addralign = L1_CACHE_BYTES; 17324af6c4eSArd Biesheuvel mod->arch.core.plt->sh_size = (core_plts + 1) * sizeof(struct plt_entry); 17424af6c4eSArd Biesheuvel mod->arch.core.plt_num_entries = 0; 17524af6c4eSArd Biesheuvel mod->arch.core.plt_max_entries = core_plts; 17624af6c4eSArd Biesheuvel 17724af6c4eSArd Biesheuvel mod->arch.init.plt->sh_type = SHT_NOBITS; 17824af6c4eSArd Biesheuvel mod->arch.init.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; 17924af6c4eSArd Biesheuvel mod->arch.init.plt->sh_addralign = L1_CACHE_BYTES; 18024af6c4eSArd Biesheuvel mod->arch.init.plt->sh_size = (init_plts + 1) * sizeof(struct plt_entry); 18124af6c4eSArd Biesheuvel mod->arch.init.plt_num_entries = 0; 18224af6c4eSArd Biesheuvel mod->arch.init.plt_max_entries = init_plts; 18324af6c4eSArd Biesheuvel 184fd045f6cSArd Biesheuvel return 0; 185fd045f6cSArd Biesheuvel } 186