diff options
author | Ard Biesheuvel <ard.biesheuvel@linaro.org> | 2016-08-16 11:21:02 -0400 |
---|---|---|
committer | Ard Biesheuvel <ard.biesheuvel@linaro.org> | 2016-08-30 12:45:34 -0400 |
commit | 35fa91eed817d2c65c59ef5a9737011313be6ac0 (patch) | |
tree | 096f2f8bf219fb1b04f28c5fc104e6331c84695a | |
parent | 3eab887a55424fc2c27553b7bfe32330df83f7b8 (diff) |
ARM: kernel: merge core and init PLTs
The PLT code uses a separate .init.plt section to allocate PLT entries
for jump and call instructions in __init code. However, even for fairly
sizable modules like mac80211.ko, we only end up with a couple of PLT
entries in the .init section, and so we can simplify the code
significantly by emitting all PLT entries into the same section.
Tested-by: Jongsung Kim <neidhard.kim@lge.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
-rw-r--r-- | arch/arm/include/asm/module.h | 6 | ||||
-rw-r--r-- | arch/arm/kernel/module-plts.c | 68 | ||||
-rw-r--r-- | arch/arm/kernel/module.lds | 3 |
3 files changed, 25 insertions, 52 deletions
diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h index e358b7966c06..464748b9fd7d 100644 --- a/arch/arm/include/asm/module.h +++ b/arch/arm/include/asm/module.h | |||
@@ -23,10 +23,8 @@ struct mod_arch_specific { | |||
23 | struct unwind_table *unwind[ARM_SEC_MAX]; | 23 | struct unwind_table *unwind[ARM_SEC_MAX]; |
24 | #endif | 24 | #endif |
25 | #ifdef CONFIG_ARM_MODULE_PLTS | 25 | #ifdef CONFIG_ARM_MODULE_PLTS |
26 | struct elf32_shdr *core_plt; | 26 | struct elf32_shdr *plt; |
27 | struct elf32_shdr *init_plt; | 27 | int plt_count; |
28 | int core_plt_count; | ||
29 | int init_plt_count; | ||
30 | #endif | 28 | #endif |
31 | }; | 29 | }; |
32 | 30 | ||
diff --git a/arch/arm/kernel/module-plts.c b/arch/arm/kernel/module-plts.c index 0c7efc3446c0..6832d1d6444e 100644 --- a/arch/arm/kernel/module-plts.c +++ b/arch/arm/kernel/module-plts.c | |||
@@ -30,28 +30,16 @@ struct plt_entries { | |||
30 | u32 lit[PLT_ENT_COUNT]; | 30 | u32 lit[PLT_ENT_COUNT]; |
31 | }; | 31 | }; |
32 | 32 | ||
33 | static bool in_init(const struct module *mod, u32 addr) | ||
34 | { | ||
35 | return addr - (u32)mod->init_layout.base < mod->init_layout.size; | ||
36 | } | ||
37 | |||
38 | u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val) | 33 | u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val) |
39 | { | 34 | { |
40 | struct plt_entries *plt, *plt_end; | 35 | struct plt_entries *plt, *plt_end; |
41 | int c, *count; | 36 | int c; |
42 | 37 | ||
43 | if (in_init(mod, loc)) { | 38 | plt = (void *)mod->arch.plt->sh_addr; |
44 | plt = (void *)mod->arch.init_plt->sh_addr; | 39 | plt_end = (void *)plt + mod->arch.plt->sh_size; |
45 | plt_end = (void *)plt + mod->arch.init_plt->sh_size; | ||
46 | count = &mod->arch.init_plt_count; | ||
47 | } else { | ||
48 | plt = (void *)mod->arch.core_plt->sh_addr; | ||
49 | plt_end = (void *)plt + mod->arch.core_plt->sh_size; | ||
50 | count = &mod->arch.core_plt_count; | ||
51 | } | ||
52 | 40 | ||
53 | /* Look for an existing entry pointing to 'val' */ | 41 | /* Look for an existing entry pointing to 'val' */ |
54 | for (c = *count; plt < plt_end; c -= PLT_ENT_COUNT, plt++) { | 42 | for (c = mod->arch.plt_count; plt < plt_end; c -= PLT_ENT_COUNT, plt++) { |
55 | int i; | 43 | int i; |
56 | 44 | ||
57 | if (!c) { | 45 | if (!c) { |
@@ -60,13 +48,13 @@ u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val) | |||
60 | { [0 ... PLT_ENT_COUNT - 1] = PLT_ENT_LDR, }, | 48 | { [0 ... PLT_ENT_COUNT - 1] = PLT_ENT_LDR, }, |
61 | { val, } | 49 | { val, } |
62 | }; | 50 | }; |
63 | ++*count; | 51 | mod->arch.plt_count++; |
64 | return (u32)plt->ldr; | 52 | return (u32)plt->ldr; |
65 | } | 53 | } |
66 | for (i = 0; i < PLT_ENT_COUNT; i++) { | 54 | for (i = 0; i < PLT_ENT_COUNT; i++) { |
67 | if (!plt->lit[i]) { | 55 | if (!plt->lit[i]) { |
68 | plt->lit[i] = val; | 56 | plt->lit[i] = val; |
69 | ++*count; | 57 | mod->arch.plt_count++; |
70 | } | 58 | } |
71 | if (plt->lit[i] == val) | 59 | if (plt->lit[i] == val) |
72 | return (u32)&plt->ldr[i]; | 60 | return (u32)&plt->ldr[i]; |
@@ -132,21 +120,19 @@ static unsigned int count_plts(Elf32_Addr base, const Elf32_Rel *rel, int num) | |||
132 | int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, | 120 | int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, |
133 | char *secstrings, struct module *mod) | 121 | char *secstrings, struct module *mod) |
134 | { | 122 | { |
135 | unsigned long core_plts = 0, init_plts = 0; | 123 | unsigned long plts = 0; |
136 | Elf32_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum; | 124 | Elf32_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum; |
137 | 125 | ||
138 | /* | 126 | /* |
139 | * To store the PLTs, we expand the .text section for core module code | 127 | * To store the PLTs, we expand the .text section for core module code |
140 | * and the .init.text section for initialization code. | 128 | * and for initialization code. |
141 | */ | 129 | */ |
142 | for (s = sechdrs; s < sechdrs_end; ++s) | 130 | for (s = sechdrs; s < sechdrs_end; ++s) |
143 | if (strcmp(".core.plt", secstrings + s->sh_name) == 0) | 131 | if (strcmp(".plt", secstrings + s->sh_name) == 0) |
144 | mod->arch.core_plt = s; | 132 | mod->arch.plt = s; |
145 | else if (strcmp(".init.plt", secstrings + s->sh_name) == 0) | ||
146 | mod->arch.init_plt = s; | ||
147 | 133 | ||
148 | if (!mod->arch.core_plt || !mod->arch.init_plt) { | 134 | if (!mod->arch.plt) { |
149 | pr_err("%s: sections missing\n", mod->name); | 135 | pr_err("%s: module PLT section missing\n", mod->name); |
150 | return -ENOEXEC; | 136 | return -ENOEXEC; |
151 | } | 137 | } |
152 | 138 | ||
@@ -158,26 +144,16 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, | |||
158 | if (s->sh_type != SHT_REL) | 144 | if (s->sh_type != SHT_REL) |
159 | continue; | 145 | continue; |
160 | 146 | ||
161 | if (strstr(secstrings + s->sh_name, ".init")) | 147 | plts += count_plts(dstsec->sh_addr, rels, numrels); |
162 | init_plts += count_plts(dstsec->sh_addr, rels, numrels); | ||
163 | else | ||
164 | core_plts += count_plts(dstsec->sh_addr, rels, numrels); | ||
165 | } | 148 | } |
166 | 149 | ||
167 | mod->arch.core_plt->sh_type = SHT_NOBITS; | 150 | mod->arch.plt->sh_type = SHT_NOBITS; |
168 | mod->arch.core_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; | 151 | mod->arch.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; |
169 | mod->arch.core_plt->sh_addralign = L1_CACHE_BYTES; | 152 | mod->arch.plt->sh_addralign = L1_CACHE_BYTES; |
170 | mod->arch.core_plt->sh_size = round_up(core_plts * PLT_ENT_SIZE, | 153 | mod->arch.plt->sh_size = round_up(plts * PLT_ENT_SIZE, |
171 | sizeof(struct plt_entries)); | 154 | sizeof(struct plt_entries)); |
172 | mod->arch.core_plt_count = 0; | 155 | mod->arch.plt_count = 0; |
173 | 156 | ||
174 | mod->arch.init_plt->sh_type = SHT_NOBITS; | 157 | pr_debug("%s: plt=%x\n", __func__, mod->arch.plt->sh_size); |
175 | mod->arch.init_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; | ||
176 | mod->arch.init_plt->sh_addralign = L1_CACHE_BYTES; | ||
177 | mod->arch.init_plt->sh_size = round_up(init_plts * PLT_ENT_SIZE, | ||
178 | sizeof(struct plt_entries)); | ||
179 | mod->arch.init_plt_count = 0; | ||
180 | pr_debug("%s: core.plt=%x, init.plt=%x\n", __func__, | ||
181 | mod->arch.core_plt->sh_size, mod->arch.init_plt->sh_size); | ||
182 | return 0; | 158 | return 0; |
183 | } | 159 | } |
diff --git a/arch/arm/kernel/module.lds b/arch/arm/kernel/module.lds index 3682fa107918..05881e2b414c 100644 --- a/arch/arm/kernel/module.lds +++ b/arch/arm/kernel/module.lds | |||
@@ -1,4 +1,3 @@ | |||
1 | SECTIONS { | 1 | SECTIONS { |
2 | .core.plt : { BYTE(0) } | 2 | .plt : { BYTE(0) } |
3 | .init.plt : { BYTE(0) } | ||
4 | } | 3 | } |