| 1 | --- a/include/elf.h |
| 2 | +++ b/include/elf.h |
| 3 | @@ -1547,6 +1547,7 @@ typedef struct |
| 4 | #define STO_MIPS_INTERNAL 0x1 |
| 5 | #define STO_MIPS_HIDDEN 0x2 |
| 6 | #define STO_MIPS_PROTECTED 0x3 |
| 7 | +#define STO_MIPS_PLT 0x8 |
| 8 | #define STO_MIPS_SC_ALIGN_UNUSED 0xff |
| 9 | |
| 10 | /* MIPS specific values for `st_info'. */ |
| 11 | @@ -1692,8 +1693,11 @@ typedef struct |
| 12 | #define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ |
| 13 | #define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ |
| 14 | #define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ |
| 15 | +#define R_MIPS_GLOB_DAT 51 |
| 16 | +#define R_MIPS_COPY 126 |
| 17 | +#define R_MIPS_JUMP_SLOT 127 |
| 18 | /* Keep this the last entry. */ |
| 19 | -#define R_MIPS_NUM 51 |
| 20 | +#define R_MIPS_NUM 128 |
| 21 | |
| 22 | /* Legal values for p_type field of Elf32_Phdr. */ |
| 23 | |
| 24 | @@ -1759,7 +1763,13 @@ typedef struct |
| 25 | #define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ |
| 26 | #define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ |
| 27 | #define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ |
| 28 | -#define DT_MIPS_NUM 0x32 |
| 29 | +/* The address of .got.plt in an executable using the new non-PIC ABI. */ |
| 30 | +#define DT_MIPS_PLTGOT 0x70000032 |
| 31 | +/* The base of the PLT in an executable using the new non-PIC ABI if that |
| 32 | + PLT is writable. For a non-writable PLT, this is omitted or has a zero |
| 33 | + value. */ |
| 34 | +#define DT_MIPS_RWPLT 0x70000034 |
| 35 | +#define DT_MIPS_NUM 0x35 |
| 36 | |
| 37 | /* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ |
| 38 | |
| 39 | --- a/ldso/ldso/dl-hash.c |
| 40 | +++ b/ldso/ldso/dl-hash.c |
| 41 | @@ -160,6 +160,11 @@ check_match (const ElfW(Sym) *sym, char |
| 42 | /* undefined symbol itself */ |
| 43 | return NULL; |
| 44 | |
| 45 | +#ifdef __mips__ |
| 46 | + if (sym->st_shndx == SHN_UNDEF && !(sym->st_other & STO_MIPS_PLT)) |
| 47 | + return NULL; |
| 48 | +#endif |
| 49 | + |
| 50 | if (sym->st_value == 0) |
| 51 | /* No value */ |
| 52 | return NULL; |
| 53 | --- a/ldso/ldso/mips/dl-sysdep.h |
| 54 | +++ b/ldso/ldso/mips/dl-sysdep.h |
| 55 | @@ -93,10 +93,11 @@ typedef struct |
| 56 | |
| 57 | #include <link.h> |
| 58 | |
| 59 | -#define ARCH_NUM 3 |
| 60 | +#define ARCH_NUM 4 |
| 61 | #define DT_MIPS_GOTSYM_IDX (DT_NUM + OS_NUM) |
| 62 | #define DT_MIPS_LOCAL_GOTNO_IDX (DT_NUM + OS_NUM +1) |
| 63 | #define DT_MIPS_SYMTABNO_IDX (DT_NUM + OS_NUM +2) |
| 64 | +#define DT_MIPS_PLTGOT_IDX (DT_NUM + OS_NUM +3) |
| 65 | |
| 66 | #define ARCH_DYNAMIC_INFO(dpnt, dynamic, debug_addr) \ |
| 67 | do { \ |
| 68 | @@ -106,6 +107,8 @@ else if (dpnt->d_tag == DT_MIPS_LOCAL_GO |
| 69 | dynamic[DT_MIPS_LOCAL_GOTNO_IDX] = dpnt->d_un.d_val; \ |
| 70 | else if (dpnt->d_tag == DT_MIPS_SYMTABNO) \ |
| 71 | dynamic[DT_MIPS_SYMTABNO_IDX] = dpnt->d_un.d_val; \ |
| 72 | +else if (dpnt->d_tag == DT_MIPS_PLTGOT) \ |
| 73 | + dynamic[DT_MIPS_PLTGOT_IDX] = dpnt->d_un.d_val; \ |
| 74 | else if (dpnt->d_tag == DT_MIPS_RLD_MAP) \ |
| 75 | *(ElfW(Addr) *)(dpnt->d_un.d_ptr) = (ElfW(Addr)) debug_addr; \ |
| 76 | } while (0) |
| 77 | @@ -114,6 +117,7 @@ else if (dpnt->d_tag == DT_MIPS_RLD_MAP) |
| 78 | #define INIT_GOT(GOT_BASE,MODULE) \ |
| 79 | do { \ |
| 80 | unsigned long idx; \ |
| 81 | + unsigned long *pltgot; \ |
| 82 | \ |
| 83 | /* Check if this is the dynamic linker itself */ \ |
| 84 | if (MODULE->libtype == program_interpreter) \ |
| 85 | @@ -123,6 +127,12 @@ do { \ |
| 86 | GOT_BASE[0] = (unsigned long) _dl_runtime_resolve; \ |
| 87 | GOT_BASE[1] = (unsigned long) MODULE; \ |
| 88 | \ |
| 89 | + pltgot = MODULE->dynamic_info[DT_MIPS_PLTGOT_IDX]; \ |
| 90 | + if (pltgot) { \ |
| 91 | + pltgot[0] = (unsigned long) _dl_runtime_pltresolve; \ |
| 92 | + pltgot[1] = (unsigned long) MODULE; \ |
| 93 | + } \ |
| 94 | + \ |
| 95 | /* Add load address displacement to all local GOT entries */ \ |
| 96 | idx = 2; \ |
| 97 | while (idx < MODULE->dynamic_info[DT_MIPS_LOCAL_GOTNO_IDX]) \ |
| 98 | @@ -157,9 +167,9 @@ void _dl_perform_mips_global_got_relocat |
| 99 | #define OFFS_ALIGN 0x7ffff000 |
| 100 | #endif /* O32 || N32 */ |
| 101 | |
| 102 | -#define elf_machine_type_class(type) ELF_RTYPE_CLASS_PLT |
| 103 | -/* MIPS does not have COPY relocs */ |
| 104 | -#define DL_NO_COPY_RELOCS |
| 105 | +#define elf_machine_type_class(type) \ |
| 106 | + ((((type) == R_MIPS_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT) \ |
| 107 | + | (((type) == R_MIPS_COPY) * ELF_RTYPE_CLASS_COPY)) |
| 108 | |
| 109 | #define OFFSET_GP_GOT 0x7ff0 |
| 110 | |
| 111 | --- a/ldso/ldso/mips/elfinterp.c |
| 112 | +++ b/ldso/ldso/mips/elfinterp.c |
| 113 | @@ -30,6 +30,7 @@ |
| 114 | #include "ldso.h" |
| 115 | |
| 116 | extern int _dl_runtime_resolve(void); |
| 117 | +extern int _dl_runtime_pltresolve(void); |
| 118 | |
| 119 | #define OFFSET_GP_GOT 0x7ff0 |
| 120 | |
| 121 | @@ -83,6 +84,61 @@ unsigned long __dl_runtime_resolve(unsig |
| 122 | return new_addr; |
| 123 | } |
| 124 | |
| 125 | +unsigned long |
| 126 | +__dl_runtime_pltresolve(struct elf_resolve *tpnt, int reloc_entry) |
| 127 | +{ |
| 128 | + int reloc_type; |
| 129 | + ELF_RELOC *this_reloc; |
| 130 | + char *strtab; |
| 131 | + Elf32_Sym *symtab; |
| 132 | + int symtab_index; |
| 133 | + char *rel_addr; |
| 134 | + char *new_addr; |
| 135 | + char **got_addr; |
| 136 | + unsigned long instr_addr; |
| 137 | + char *symname; |
| 138 | + |
| 139 | + rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL]; |
| 140 | + this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry); |
| 141 | + reloc_type = ELF32_R_TYPE(this_reloc->r_info); |
| 142 | + symtab_index = ELF32_R_SYM(this_reloc->r_info); |
| 143 | + |
| 144 | + symtab = (Elf32_Sym *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB]; |
| 145 | + strtab = (char *)tpnt->dynamic_info[DT_STRTAB]; |
| 146 | + symname = strtab + symtab[symtab_index].st_name; |
| 147 | + |
| 148 | + /* Address of the jump instruction to fix up. */ |
| 149 | + instr_addr = ((unsigned long)this_reloc->r_offset + |
| 150 | + (unsigned long)tpnt->loadaddr); |
| 151 | + got_addr = (char **)instr_addr; |
| 152 | + |
| 153 | + /* Get the address of the GOT entry. */ |
| 154 | + new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT); |
| 155 | + if (unlikely(!new_addr)) { |
| 156 | + _dl_dprintf(2, "%s: can't resolve symbol '%s' in lib '%s'.\n", _dl_progname, symname, tpnt->libname); |
| 157 | + _dl_exit(1); |
| 158 | + } |
| 159 | + |
| 160 | +#if defined (__SUPPORT_LD_DEBUG__) |
| 161 | + if ((unsigned long)got_addr < 0x40000000) { |
| 162 | + if (_dl_debug_bindings) { |
| 163 | + _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname); |
| 164 | + if (_dl_debug_detail) |
| 165 | + _dl_dprintf(_dl_debug_file, |
| 166 | + "\n\tpatched: %x ==> %x @ %x", |
| 167 | + *got_addr, new_addr, got_addr); |
| 168 | + } |
| 169 | + } |
| 170 | + if (!_dl_debug_nofixups) { |
| 171 | + *got_addr = new_addr; |
| 172 | + } |
| 173 | +#else |
| 174 | + *got_addr = new_addr; |
| 175 | +#endif |
| 176 | + |
| 177 | + return (unsigned long)new_addr; |
| 178 | +} |
| 179 | + |
| 180 | void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, |
| 181 | unsigned long rel_addr, unsigned long rel_size) |
| 182 | { |
| 183 | @@ -115,6 +171,7 @@ int _dl_parse_relocation_information(str |
| 184 | got = (unsigned long *) tpnt->dynamic_info[DT_PLTGOT]; |
| 185 | |
| 186 | for (i = 0; i < rel_size; i++, rpnt++) { |
| 187 | + char *symname = NULL; |
| 188 | reloc_addr = (unsigned long *) (tpnt->loadaddr + |
| 189 | (unsigned long) rpnt->r_offset); |
| 190 | reloc_type = ELF_R_TYPE(rpnt->r_info); |
| 191 | @@ -128,6 +185,16 @@ int _dl_parse_relocation_information(str |
| 192 | old_val = *reloc_addr; |
| 193 | #endif |
| 194 | |
| 195 | + if (reloc_type == R_MIPS_JUMP_SLOT || reloc_type == R_MIPS_COPY) { |
| 196 | + symname = strtab + symtab[symtab_index].st_name; |
| 197 | + symbol_addr = (unsigned long)_dl_find_hash(symname, |
| 198 | + tpnt->symbol_scope, |
| 199 | + tpnt, |
| 200 | + elf_machine_type_class(reloc_type)); |
| 201 | + if (unlikely(!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) |
| 202 | + return 1; |
| 203 | + } |
| 204 | + |
| 205 | switch (reloc_type) { |
| 206 | #if _MIPS_SIM == _MIPS_SIM_ABI64 |
| 207 | case (R_MIPS_64 << 8) | R_MIPS_REL32: |
| 208 | @@ -148,6 +215,24 @@ int _dl_parse_relocation_information(str |
| 209 | *reloc_addr += (unsigned long) tpnt->loadaddr; |
| 210 | } |
| 211 | break; |
| 212 | + case R_MIPS_JUMP_SLOT: |
| 213 | + *reloc_addr = symbol_addr; |
| 214 | + break; |
| 215 | + case R_MIPS_COPY: |
| 216 | + if (symbol_addr) { |
| 217 | +#if defined (__SUPPORT_LD_DEBUG__) |
| 218 | + if (_dl_debug_move) |
| 219 | + _dl_dprintf(_dl_debug_file, |
| 220 | + "\n%s move %d bytes from %x to %x", |
| 221 | + symname, symtab[symtab_index].st_size, |
| 222 | + symbol_addr, reloc_addr); |
| 223 | +#endif |
| 224 | + |
| 225 | + _dl_memcpy((char *)reloc_addr, |
| 226 | + (char *)symbol_addr, |
| 227 | + symtab[symtab_index].st_size); |
| 228 | + } |
| 229 | + break; |
| 230 | case R_MIPS_NONE: |
| 231 | break; |
| 232 | default: |
| 233 | --- a/ldso/ldso/mips/resolve.S |
| 234 | +++ b/ldso/ldso/mips/resolve.S |
| 235 | @@ -112,3 +112,54 @@ _dl_runtime_resolve: |
| 236 | .end _dl_runtime_resolve |
| 237 | .previous |
| 238 | |
| 239 | +/* Assembler veneer called from the PLT header code when using the |
| 240 | + non-PIC ABI. |
| 241 | + |
| 242 | + Code in each PLT entry puts the caller's return address into t7 ($15), |
| 243 | + the PLT entry index into t8 ($24), the address of _dl_runtime_pltresolve |
| 244 | + into t9 ($25) and the address of .got.plt into gp ($28). __dl_runtime_pltresolve |
| 245 | + needs a0 ($4) to hold the link map and a1 ($5) to hold the index into |
| 246 | + .rel.plt (== PLT entry index * 4). */ |
| 247 | + |
| 248 | + .text |
| 249 | + .align 2 |
| 250 | + .globl _dl_runtime_pltresolve |
| 251 | + .type _dl_runtime_pltresolve,@function |
| 252 | + .ent _dl_runtime_pltresolve |
| 253 | +_dl_runtime_pltresolve: |
| 254 | + .frame $29, 40, $31 |
| 255 | + .set noreorder |
| 256 | + # Save arguments and sp value in stack. |
| 257 | + subu $29, 40 |
| 258 | + lw $10, 4($28) |
| 259 | + # Modify t9 ($25) so as to point .cpload instruction. |
| 260 | + addiu $25, 12 |
| 261 | + # Compute GP. |
| 262 | + .cpload $25 |
| 263 | + .set reorder |
| 264 | + |
| 265 | + /* Store function arguments from registers to stack */ |
| 266 | + sw $15, 36($29) |
| 267 | + sw $4, 16($29) |
| 268 | + sw $5, 20($29) |
| 269 | + sw $6, 24($29) |
| 270 | + sw $7, 28($29) |
| 271 | + |
| 272 | + /* Setup functions args and call __dl_runtime_pltresolve. */ |
| 273 | + move $4, $10 |
| 274 | + sll $5, $24, 3 |
| 275 | + jal __dl_runtime_pltresolve |
| 276 | + |
| 277 | + /* Restore function arguments from stack to registers */ |
| 278 | + lw $31, 36($29) |
| 279 | + lw $4, 16($29) |
| 280 | + lw $5, 20($29) |
| 281 | + lw $6, 24($29) |
| 282 | + lw $7, 28($29) |
| 283 | + |
| 284 | + /* Do a tail call to the original function */ |
| 285 | + addiu $29, 40 |
| 286 | + move $25, $2 |
| 287 | + jr $25 |
| 288 | + .end _dl_runtime_pltresolve |
| 289 | + .previous |
| 290 | |