2 /* Run an ELF binary on a linux system.
4 Copyright (C) 1993, Eric Youngdale.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20 #ifndef VERBOSE_DLINKER
21 #define VERBOSE_DLINKER
23 #ifdef VERBOSE_DLINKER
24 static char *_dl_reltypes[] =
25 { "R_PPC_NONE", "R_PPC_ADDR32", "R_PPC_ADDR24", "R_PPC_ADDR16",
26 "R_PPC_ADDR16_LO", "R_PPC_ADDR16_HI", "R_PPC_ADDR16_HA",
27 "R_PPC_ADDR14", "R_PPC_ADDR14_BRTAKEN", "R_PPC_ADDR14_BRNTAKEN",
28 "R_PPC_REL24", "R_PPC_REL14", "R_PPC_REL14_BRTAKEN",
29 "R_PPC_REL14_BRNTAKEN", "R_PPC_GOT16", "R_PPC_GOT16_LO",
30 "R_PPC_GOT16_HI", "R_PPC_GOT16_HA", "R_PPC_PLTREL24",
31 "R_PPC_COPY", "R_PPC_GLOB_DAT", "R_PPC_JMP_SLOT", "R_PPC_RELATIVE",
32 "R_PPC_LOCAL24PC", "R_PPC_UADDR32", "R_PPC_UADDR16", "R_PPC_REL32",
33 "R_PPC_PLT32", "R_PPC_PLTREL32", "R_PPC_PLT16_LO", "R_PPC_PLT16_HI",
34 "R_PPC_PLT16_HA", "R_PPC_SDAREL16", "R_PPC_SECTOFF",
35 "R_PPC_SECTOFF_LO", "R_PPC_SECTOFF_HI", "R_PPC_SECTOFF_HA",
37 #define N_RELTYPES (sizeof(_dl_reltypes)/sizeof(_dl_reltypes[0]))
40 /* Program to load an ELF binary on a linux system, and run it.
41 References to symbols in sharable libraries can be resolved by either
42 an ELF sharable library or a linux style of shared library. */
44 /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
45 I ever taken any courses on internals. This program was developed using
46 information available through the book "UNIX SYSTEM V RELEASE 4,
47 Programmers guide: Ansi C and Programming Support Tools", which did
48 a more than adequate job of explaining everything required to get this
52 #ifdef DL_DEBUG_SYMBOLS
53 static void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index);
54 static void debug_reloc(ELF_RELOC *rpnt);
55 #define DPRINTF(fmt,args...) _dl_dprintf(2,fmt,args)
57 #define debug_sym(a,b,c)
58 #define debug_reloc(a)
59 #define DPRINTF(fmt,args...)
62 extern int _dl_linux_resolve(void);
64 void _dl_init_got(unsigned long *plt,struct elf_resolve *tpnt)
66 unsigned long target_addr = (unsigned long)_dl_linux_resolve;
67 unsigned int n_plt_entries;
69 unsigned long data_words;
70 unsigned int rel_offset_words;
72 DPRINTF("init_got plt=%x, tpnt=%x\n",
73 (unsigned long)plt,(unsigned long)tpnt);
75 n_plt_entries = tpnt->dynamic_info[DT_PLTRELSZ] / sizeof(ELF_RELOC);
76 DPRINTF("n_plt_entries %d\n",n_plt_entries);
78 rel_offset_words = PLT_DATA_START_WORDS(n_plt_entries);
79 DPRINTF("rel_offset_words %x\n",rel_offset_words);
80 data_words = (unsigned long)(plt + rel_offset_words);
81 DPRINTF("data_words %x\n",data_words);
83 tpnt->data_words = data_words;
85 plt[PLT_LONGBRANCH_ENTRY_WORDS] = OPCODE_ADDIS_HI(11, 11, data_words);
86 plt[PLT_LONGBRANCH_ENTRY_WORDS+1] = OPCODE_LWZ(11,data_words,11);
88 plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR(11);
89 plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR();
94 tramp = plt + PLT_TRAMPOLINE_ENTRY_WORDS;
95 tramp[0] = OPCODE_ADDIS_HI(11,11,-data_words);
96 tramp[1] = OPCODE_ADDI(11,11,-data_words);
97 tramp[2] = OPCODE_SLWI(12,11,1);
98 tramp[3] = OPCODE_ADD(11,12,11);
99 tramp[4] = OPCODE_LI(12,target_addr);
100 tramp[5] = OPCODE_ADDIS_HI(12,12,target_addr);
101 tramp[6] = OPCODE_MTCTR(12);
102 tramp[7] = OPCODE_LI(12,(unsigned long)tpnt);
103 tramp[8] = OPCODE_ADDIS_HI(12,12,(unsigned long)tpnt);
104 tramp[9] = OPCODE_BCTR();
109 /* instructions were modified */
120 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
123 ELF_RELOC *this_reloc;
128 unsigned long insn_addr;
129 unsigned long *insns;
130 unsigned long targ_addr;
133 //DPRINTF("linux_resolver tpnt=%x reloc_entry=%x\n", tpnt, reloc_entry);
135 rel_addr = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
137 this_reloc = (void *)rel_addr + reloc_entry;
138 reloc_type = ELF32_R_TYPE(this_reloc->r_info);
139 symtab_index = ELF32_R_SYM(this_reloc->r_info);
141 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
142 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
144 //debug_reloc(this_reloc);
146 if (reloc_type != R_PPC_JMP_SLOT) {
147 _dl_dprintf(2, "%s: Incorrect relocation type [%s] in jump relocations\n",
149 (reloc_type<N_RELTYPES)?_dl_reltypes[reloc_type]:"unknown");
153 /* Address of dump instruction to fix up */
154 insn_addr = (unsigned long) tpnt->loadaddr +
155 (unsigned long) this_reloc->r_offset;
157 DPRINTF("Resolving symbol %s %x --> ",
158 strtab + symtab[symtab_index].st_name,
161 /* Get the address of the GOT entry */
162 targ_addr = (unsigned long) _dl_find_hash(
163 strtab + symtab[symtab_index].st_name,
164 tpnt->symbol_scope, insn_addr, tpnt, 0);
166 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
167 _dl_progname, strtab + symtab[symtab_index].st_name);
170 DPRINTF("%x\n", targ_addr);
172 insns = (unsigned long *)insn_addr;
173 delta = targ_addr - insn_addr;
175 if(delta<<6>>6 == delta){
176 insns[0] = OPCODE_B(delta);
177 }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
178 insns[0] = OPCODE_BA (targ_addr);
180 /* Warning: we don't handle double-sized PLT entries */
181 unsigned long plt_addr;
182 unsigned long lbranch_addr;
186 plt_addr = (unsigned long)tpnt->dynamic_info[DT_PLTGOT] +
187 (unsigned long)tpnt->loadaddr;
188 lbranch_addr = plt_addr + PLT_LONGBRANCH_ENTRY_WORDS*4;
189 delta = lbranch_addr - insn_addr;
190 index = (insn_addr - plt_addr - PLT_INITIAL_ENTRY_WORDS*4)/8;
192 ptr = (unsigned long *)tpnt->data_words;
193 DPRINTF("plt_addr=%x delta=%x index=%x ptr=%x\n",
194 plt_addr, delta, index, ptr);
195 ptr[index] = targ_addr;
196 /* icache sync is not necessary, since this will be a data load */
197 //PPC_DCBST(ptr+index);
199 //PPC_ICBI(ptr+index);
201 insns[1] = OPCODE_B(delta - 4);
204 /* instructions were modified */
205 PPC_DCBST(insn_addr);
213 void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
214 unsigned long rel_addr, unsigned long rel_size, int type)
222 unsigned long reloc_addr;
223 unsigned long *insns;
227 DPRINTF("_dl_parse_lazy_relocation_information(tpnt=%x, rel_addr=%x, rel_size=%x, type=%d)\n",
228 tpnt,rel_addr,rel_size,type);
230 /* Now parse the relocation information */
231 rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
232 rel_size = rel_size / sizeof(ELF_RELOC);
234 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
235 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
236 plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
238 for (i = 0; i < rel_size; i++, rpnt++) {
239 reloc_addr = (unsigned long)tpnt->loadaddr +
240 (unsigned long) rpnt->r_offset;
241 reloc_type = ELF32_R_TYPE(rpnt->r_info);
242 symtab_index = ELF32_R_SYM(rpnt->r_info);
244 /* When the dynamic linker bootstrapped itself, it resolved some symbols.
245 Make sure we do not do them again */
246 if (!symtab_index && tpnt->libtype == program_interpreter)
248 if (symtab_index && tpnt->libtype == program_interpreter &&
249 _dl_symbol(strtab + symtab[symtab_index].st_name))
252 DPRINTF("L %x %s %s %x %x\n",
253 reloc_addr, _dl_reltypes[reloc_type],
254 symtab_index?strtab + symtab[symtab_index].st_name:"",0,0);
256 switch (reloc_type) {
263 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
266 index = (reloc_addr -
267 (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
268 /sizeof(unsigned long);
270 DPRINTF(" index %x delta %x\n",index,delta);
271 insns = (unsigned long *)reloc_addr;
272 insns[0] = OPCODE_LI(11,index*4);
273 insns[1] = OPCODE_B(delta);
277 _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ",
279 #ifdef VERBOSE_DLINKER
280 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
283 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
287 /* instructions were modified */
288 PPC_DCBST(reloc_addr);
290 PPC_ICBI(reloc_addr);
294 int _dl_parse_relocation_information(struct elf_resolve *tpnt,
295 unsigned long rel_addr, unsigned long rel_size, int type)
303 unsigned long *reloc_addr;
304 unsigned long symbol_addr;
306 unsigned long addend;
309 DPRINTF("_dl_parse_relocation_information(tpnt=%x, rel_addr=%x, rel_size=%x, type=%d)\n",
310 tpnt,rel_addr,rel_size,type);
312 /* Now parse the relocation information */
314 rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
315 rel_size = rel_size / sizeof(ELF_RELOC);
317 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
318 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
319 plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
321 for (i = 0; i < rel_size; i++, rpnt++) {
324 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
325 reloc_type = ELF32_R_TYPE(rpnt->r_info);
326 symtab_index = ELF32_R_SYM(rpnt->r_info);
327 addend = rpnt->r_addend;
330 if (!symtab_index && tpnt->libtype == program_interpreter)
335 if (tpnt->libtype == program_interpreter &&
336 _dl_symbol(strtab + symtab[symtab_index].st_name))
339 symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name,
340 tpnt->symbol_scope, (unsigned long) reloc_addr,
341 (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL), 0);
344 * We want to allow undefined references to weak symbols - this might
345 * have been intentional. We should not be linking local symbols
346 * here, so all bases should be covered.
349 ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
350 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
351 _dl_progname, strtab + symtab[symtab_index].st_name);
355 debug_sym(symtab,strtab,symtab_index);
357 switch (reloc_type) {
362 int delta = symbol_addr - (unsigned long)reloc_addr;
363 if(delta<<6>>6 != delta){
364 _dl_dprintf(2,"R_PPC_REL24: Reloc out of range\n");
367 *reloc_addr &= 0xfc000003;
368 *reloc_addr |= delta&0x03fffffc;
372 *reloc_addr = (unsigned long)tpnt->loadaddr + addend;
375 *reloc_addr += symbol_addr;
377 case R_PPC_ADDR16_HA:
378 /* XXX is this correct? */
379 *(short *)reloc_addr += (symbol_addr+0x8000)>>16;
381 case R_PPC_ADDR16_HI:
382 *(short *)reloc_addr += symbol_addr>>16;
384 case R_PPC_ADDR16_LO:
385 *(short *)reloc_addr += symbol_addr;
389 unsigned long targ_addr = (unsigned long)_dl_linux_resolve;
390 int delta = targ_addr - (unsigned long)reloc_addr;
391 if(delta<<6>>6 == delta){
392 *reloc_addr = OPCODE_B(delta);
393 }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
394 *reloc_addr = OPCODE_BA (targ_addr);
400 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
401 - (unsigned long)(reloc_addr+1);
403 index = ((unsigned long)reloc_addr -
404 (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
405 /sizeof(unsigned long);
407 DPRINTF(" index %x delta %x\n",index,delta);
408 reloc_addr[0] = OPCODE_LI(11,index*4);
409 reloc_addr[1] = OPCODE_B(delta);
415 *reloc_addr += symbol_addr;
421 _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
422 #ifdef VERBOSE_DLINKER
423 _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
426 _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
430 /* instructions were modified */
431 PPC_DCBST(reloc_addr);
433 PPC_ICBI(reloc_addr);
435 DPRINTF("reloc_addr %x: %x\n",reloc_addr,*reloc_addr);
441 /* This is done as a separate step, because there are cases where
442 information is first copied and later initialized. This results in
443 the wrong information being copied. Someone at Sun was complaining about
444 a bug in the handling of _COPY by SVr4, and this may in fact be what he
445 was talking about. Sigh. */
447 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
450 int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
451 unsigned long rel_size, int type)
459 unsigned long *reloc_addr;
460 unsigned long symbol_addr;
461 struct elf_resolve *tpnt;
464 DPRINTF("parse_copy xpnt=%x rel_addr=%x rel_size=%x type=%d\n",
465 (int)xpnt,rel_addr,rel_size,type);
467 /* Now parse the relocation information */
471 rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
472 rel_size = rel_size / sizeof(ELF_RELOC);
474 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
475 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
477 for (i = 0; i < rel_size; i++, rpnt++) {
478 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
479 reloc_type = ELF32_R_TYPE(rpnt->r_info);
480 if (reloc_type != R_PPC_COPY)
485 symtab_index = ELF32_R_SYM(rpnt->r_info);
487 if (!symtab_index && tpnt->libtype == program_interpreter)
491 if (tpnt->libtype == program_interpreter &&
492 _dl_symbol(strtab + symtab[symtab_index].st_name))
495 symbol_addr = (unsigned long) _dl_find_hash(strtab +
496 symtab[symtab_index].st_name, xpnt->next,
497 (unsigned long) reloc_addr, NULL, 1);
499 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
500 _dl_progname, strtab + symtab[symtab_index].st_name);
505 debug_sym(symtab,strtab,symtab_index);
507 DPRINTF("copy: to=%x from=%x size=%x\n",
508 symtab[symtab_index].st_value,
509 symbol_addr, symtab[symtab_index].st_size);
512 _dl_memcpy((char *) symtab[symtab_index].st_value,
513 (char *) symbol_addr,
514 symtab[symtab_index].st_size);
522 static void fixup_jmpslot(unsigned long reloc_addr, unsigned long targ_addr)
524 int delta = targ_addr - reloc_addr;
527 if(delta<<6>>6 == delta){
528 *reloc_addr = OPCODE_B(delta);
529 }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
530 *reloc_addr = OPCODE_BA (targ_addr);
532 delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2)
533 - (unsigned long)(reloc_addr+1);
535 index = ((unsigned long)reloc_addr -
536 (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
537 /sizeof(unsigned long);
540 DPRINTF(" index %x delta %x\n",index,delta);
542 reloc_addr[0] = OPCODE_LI(11,index*4);
543 reloc_addr[1] = OPCODE_B(delta);
549 #ifdef DL_DEBUG_SYMBOLS
550 static void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
553 _dl_dprintf(2, "sym: name=%s value=%x size=%x info=%x other=%x shndx=%x\n",
554 strtab + symtab[symtab_index].st_name,
555 symtab[symtab_index].st_value,
556 symtab[symtab_index].st_size,
557 symtab[symtab_index].st_info,
558 symtab[symtab_index].st_other,
559 symtab[symtab_index].st_shndx);
561 _dl_dprintf(2, "sym: null\n");
565 static void debug_reloc(ELF_RELOC *rpnt)
567 _dl_dprintf(2, "reloc: offset=%x type=%x sym=%x addend=%x\n",
569 ELF32_R_TYPE(rpnt->r_info),
570 ELF32_R_SYM(rpnt->r_info),