| 1 |
|
| 2 | |
| 3 | * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
|
| 4 |
|
| 5 | #ifndef _ASM_MODULE_H
|
| 6 | #define _ASM_MODULE_H
|
| 7 |
|
| 8 | #include <asm/inst.h>
|
| 9 | #include <asm/orc_types.h>
|
| 10 | #include <asm-generic/module.h>
|
| 11 |
|
| 12 | #define RELA_STACK_DEPTH 16
|
| 13 |
|
| 14 | struct mod_section {
|
| 15 | int shndx;
|
| 16 | int num_entries;
|
| 17 | int max_entries;
|
| 18 | };
|
| 19 |
|
| 20 | struct mod_arch_specific {
|
| 21 | struct mod_section got;
|
| 22 | struct mod_section plt;
|
| 23 | struct mod_section plt_idx;
|
| 24 |
|
| 25 | #ifdef CONFIG_UNWINDER_ORC
|
| 26 | unsigned int num_orcs;
|
| 27 | int *orc_unwind_ip;
|
| 28 | struct orc_entry *orc_unwind;
|
| 29 | #endif
|
| 30 |
|
| 31 |
|
| 32 | struct plt_entry *ftrace_trampolines;
|
| 33 | };
|
| 34 |
|
| 35 | struct got_entry {
|
| 36 | Elf_Addr symbol_addr;
|
| 37 | };
|
| 38 |
|
| 39 | struct plt_entry {
|
| 40 | u32 inst_lu12iw;
|
| 41 | #ifdef CONFIG_64BIT
|
| 42 | u32 inst_lu32id;
|
| 43 | u32 inst_lu52id;
|
| 44 | #endif
|
| 45 | u32 inst_jirl;
|
| 46 | };
|
| 47 |
|
| 48 | struct plt_idx_entry {
|
| 49 | Elf_Addr symbol_addr;
|
| 50 | };
|
| 51 |
|
| 52 | Elf_Addr module_emit_got_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val);
|
| 53 | Elf_Addr module_emit_plt_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val);
|
| 54 |
|
| 55 | static inline struct got_entry emit_got_entry(Elf_Addr val)
|
| 56 | {
|
| 57 | return (struct got_entry) { val };
|
| 58 | }
|
| 59 |
|
| 60 | static inline struct plt_entry emit_plt_entry(unsigned long val)
|
| 61 | {
|
| 62 | #ifdef CONFIG_32BIT
|
| 63 | u32 lu12iw, jirl;
|
| 64 |
|
| 65 | lu12iw = larch_insn_gen_lu12iw(LOONGARCH_GPR_T1, ADDR_IMM(val, LU12IW));
|
| 66 | jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, ADDR_IMM(val, ORI));
|
| 67 |
|
| 68 | return (struct plt_entry) { lu12iw, jirl };
|
| 69 | #else
|
| 70 | u32 lu12iw, lu32id, lu52id, jirl;
|
| 71 |
|
| 72 | lu12iw = larch_insn_gen_lu12iw(LOONGARCH_GPR_T1, ADDR_IMM(val, LU12IW));
|
| 73 | lu32id = larch_insn_gen_lu32id(LOONGARCH_GPR_T1, ADDR_IMM(val, LU32ID));
|
| 74 | lu52id = larch_insn_gen_lu52id(LOONGARCH_GPR_T1, LOONGARCH_GPR_T1, ADDR_IMM(val, LU52ID));
|
| 75 | jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, ADDR_IMM(val, ORI));
|
| 76 |
|
| 77 | return (struct plt_entry) { lu12iw, lu32id, lu52id, jirl };
|
| 78 | #endif
|
| 79 | }
|
| 80 |
|
| 81 | static inline struct plt_idx_entry emit_plt_idx_entry(unsigned long val)
|
| 82 | {
|
| 83 | return (struct plt_idx_entry) { val };
|
| 84 | }
|
| 85 |
|
| 86 | static inline int get_plt_idx(unsigned long val, Elf_Shdr *sechdrs, const struct mod_section *sec)
|
| 87 | {
|
| 88 | int i;
|
| 89 | struct plt_idx_entry *plt_idx = (struct plt_idx_entry *)sechdrs[sec->shndx].sh_addr;
|
| 90 |
|
| 91 | for (i = 0; i < sec->num_entries; i++) {
|
| 92 | if (plt_idx[i].symbol_addr == val)
|
| 93 | return i;
|
| 94 | }
|
| 95 |
|
| 96 | return -1;
|
| 97 | }
|
| 98 |
|
| 99 | static inline struct plt_entry *get_plt_entry(unsigned long val,
|
| 100 | Elf_Shdr *sechdrs,
|
| 101 | const struct mod_section *sec_plt,
|
| 102 | const struct mod_section *sec_plt_idx)
|
| 103 | {
|
| 104 | int plt_idx = get_plt_idx(val, sechdrs, sec_plt_idx);
|
| 105 | struct plt_entry *plt = (struct plt_entry *)sechdrs[sec_plt->shndx].sh_addr;
|
| 106 |
|
| 107 | if (plt_idx < 0)
|
| 108 | return NULL;
|
| 109 |
|
| 110 | return plt + plt_idx;
|
| 111 | }
|
| 112 |
|
| 113 | static inline struct got_entry *get_got_entry(Elf_Addr val,
|
| 114 | Elf_Shdr *sechdrs,
|
| 115 | const struct mod_section *sec)
|
| 116 | {
|
| 117 | int i;
|
| 118 | struct got_entry *got = (struct got_entry *)sechdrs[sec->shndx].sh_addr;
|
| 119 |
|
| 120 | for (i = 0; i < sec->num_entries; i++)
|
| 121 | if (got[i].symbol_addr == val)
|
| 122 | return &got[i];
|
| 123 | return NULL;
|
| 124 | }
|
| 125 |
|
| 126 | #endif
|