Example #1
0
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;
		}
	}
}
Example #2
0
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));
}
Example #3
0
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;
	}
}