void ld_dynamic_load_dso_dynamic(struct ld *ld, struct ld_input *li, Elf *e, Elf_Scn *scn, size_t strndx) { GElf_Shdr shdr; GElf_Dyn dyn; Elf_Data *d; int elferr, i, len; const char *name; if (strndx == SHN_UNDEF) return; if (gelf_getshdr(scn, &shdr) != &shdr) { ld_warn(ld, "%s: gelf_getshdr failed: %s", li->li_name, elf_errmsg(-1)); return; } (void) elf_errno(); if ((d = elf_getdata(scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) ld_warn(ld, "%s: elf_getdata failed: %s", li->li_name, elf_errmsg(elferr)); return; } len = d->d_size / shdr.sh_entsize; for (i = 0; i < len; i++) { if (gelf_getdyn(d, i, &dyn) != &dyn) { ld_warn(ld, "%s: gelf_getdyn failed: %s", li->li_name, elf_errmsg(-1)); continue; } switch (dyn.d_tag) { case DT_SONAME: name = elf_strptr(e, strndx, dyn.d_un.d_ptr); if (name != NULL && (li->li_soname = strdup(name)) == NULL) ld_fatal_std(ld, "strdup"); break; case DT_NEEDED: name = elf_strptr(e, strndx, dyn.d_un.d_ptr); if (name != NULL) ld_path_search_dso_needed(ld, li->li_file, name); break; default: break; } } }
static void _warn_pic(struct ld *ld, struct ld_reloc_entry *lre) { struct ld_symbol *lsb; lsb = lre->lre_sym; if (lsb->lsb_bind != STB_LOCAL) ld_warn(ld, "relocation %s against `%s' can not be used" " by runtime linker; recompile with -fPIC", _reloc2str(lre->lre_type), lsb->lsb_name); else ld_warn(ld, "relocation %s can not be used by runtime linker;" " recompile with -fPIC", _reloc2str(lre->lre_type)); }
static void _scan_reloc(struct ld *ld, struct ld_input_section *is, struct ld_reloc_entry *lre) { struct ld_symbol *lsb; lsb = ld_symbols_ref(lre->lre_sym); switch (lre->lre_type) { case R_386_NONE: break; case R_386_32: /* * For a local symbol, if te linker output a PIE or DSO, * we should generate a R_386_RELATIVE reloc for R_386_32. */ if (lsb->lsb_bind == STB_LOCAL) { if (ld->ld_pie || ld->ld_dso) _create_dynamic_reloc(ld, is, lsb, R_386_RELATIVE, lre->lre_offset); break; } /* * For a global symbol, we probably need to generate PLE entry * and/ore a dynamic relocation. * * Note here, normally the compiler will generate a PC-relative * relocation for function calls. However, if the code retrieve * the address of a function and call it indirectly, assembler * will generate absolute relocation instead. That's why we * should check if we need to create a PLT entry here. Also, if * we're going to create the PLT entry, we should also set the * symbol value to the address of PLT entry just in case the * function address is used to compare with other function * addresses. (If PLT address is used, function will have * unified address in the main executable and DSOs) */ if (ld_reloc_require_plt(ld, lre)) { if (!lsb->lsb_plt) { _reserve_gotplt_entry(ld, lsb); _reserve_plt_entry(ld, lsb); } /* * Note here even if we have generated PLT for this * function before, we still need to set this flag. * It's possible that we first see the relative * relocation then this absolute relocation, in * other words, the same function can be called in * different ways. */ lsb->lsb_func_addr = 1; } if (ld_reloc_require_copy_reloc(ld, lre) && !lsb->lsb_copy_reloc) _create_copy_reloc(ld, lsb); else if (ld_reloc_require_dynamic_reloc(ld, lre)) { /* * Check if we can relax R_386_32 to * R_386_RELATIVE instead. */ if (ld_reloc_relative_relax(ld, lre)) _create_dynamic_reloc(ld, is, lsb, R_386_RELATIVE, lre->lre_offset); else _create_dynamic_reloc(ld, is, lsb, R_386_32, lre->lre_offset); } break; case R_386_PLT32: /* * In some cases we don't really need to generate a PLT * entry, then a R_386_PLT32 relocation can be relaxed * to a R_386_PC32 relocation. */ if (lsb->lsb_bind == STB_LOCAL || !ld_reloc_require_plt(ld, lre)) { lre->lre_type = R_386_PC32; break; } /* * If linker outputs an normal executable and the symbol is * defined but is not defined inside a DSO, we can generate * a R_386_PC32 relocation instead. */ if (ld->ld_exec && lsb->lsb_shndx != SHN_UNDEF && (lsb->lsb_input == NULL || lsb->lsb_input->li_type != LIT_DSO)) { lre->lre_type = R_386_PC32; break; } /* Create an PLT entry otherwise. */ if (!lsb->lsb_plt) { _reserve_gotplt_entry(ld, lsb); _reserve_plt_entry(ld, lsb); } break; case R_386_PC32: /* * When R_386_PC32 apply to a global symbol, we should * check if we need to generate PLT entry and/or a dynamic * relocation. */ if (lsb->lsb_bind != STB_LOCAL) { if (ld_reloc_require_plt(ld, lre) && !lsb->lsb_plt) { _reserve_gotplt_entry(ld, lsb); _reserve_plt_entry(ld, lsb); } if (ld_reloc_require_copy_reloc(ld, lre) && !lsb->lsb_copy_reloc) _create_copy_reloc(ld, lsb); else if (ld_reloc_require_dynamic_reloc(ld, lre)) { /* * We can not generate dynamic relocation for * these PC-relative relocation since they * are probably not supported by the runtime * linkers. */ _warn_pic(ld, lre); } } break; case R_386_GOTOFF: case R_386_GOTPC: /* * These relocation types use GOT address as a base address * and instruct the linker to build a GOT. */ (void) _find_and_create_got_section(ld, 1); break; case R_386_GOT32: /* * R_386_GOT32 relocation instructs the linker to build a * GOT and generate a GOT entry. */ if (!lsb->lsb_got) { _reserve_got_entry(ld, lsb, 1); /* * TODO: For now we always create a R_386_GLOB_DAT * relocation for a GOT entry. There are cases that * the symbol's address is known at link time and * the GOT entry value can be filled in by the program * linker instead. */ if (ld_reloc_require_glob_dat(ld, lre)) _create_got_reloc(ld, lsb, R_386_GLOB_DAT, lsb->lsb_got_off); else _create_got_reloc(ld, lsb, R_386_RELATIVE, lsb->lsb_got_off); } default: ld_warn(ld, "can not handle relocation %ju", lre->lre_type); break; } }