Exemplo n.º 1
0
Arquivo: elf.c Projeto: rui314/8cc-old
static void add_reloc(Elf *elf) {
    char name[100];
    for (int i = 0; i < LIST_LEN(elf->sections); i++) {
        Section *sect = LIST_REF(elf->sections, i);
        if (LIST_LEN(sect->rels) == 0)
            continue;
        String *b = make_string();
        for (int j = 0; j < LIST_LEN(sect->rels); j++) {
            Reloc *rel = LIST_REF(sect->rels, j);
            o8(b, rel->off);
            if (rel->sym) {
                o8(b, ELF64_R_INFO(find_symbol(elf, rel->sym)->index, rel->type));
            } else {
                o8(b, ELF64_R_INFO(rel->section->symindex, rel->type));
            }
            o8(b, rel->addend);
        }

        strcpy(name, ".rela");
        strcpy(name + 5, sect->name);
        Section *relsec = make_section(name, SHT_RELA);
        relsec->link = elf->symtabnum;
        relsec->info = i + 1;
        relsec->body = b;
        relsec->entsize = 24;
        relsec->align = 4;
        add_section(elf, relsec);
    }
}
Exemplo n.º 2
0
int elfrw_read_Rela(FILE *fp, Elf64_Rela *in)
{
    int r;

    if (is64bit_form()) {
        r = fread(in, sizeof *in, 1, fp);
        if (r == 1) {
            if (!native_form()) {
                revinplc_64xword(&in->r_offset);
                revinplc_64xword(&in->r_info);
                revinplc_64xword(&in->r_addend);
            }
        }
    } else {
        Elf32_Rela in32;
        r = fread(&in32, sizeof in32, 1, fp);
        if (r == 1) {
            if (native_form()) {
                in->r_offset = in32.r_offset;
                in->r_info = ELF64_R_INFO(ELF32_R_SYM(in32.r_info),
                                          ELF32_R_TYPE(in32.r_info));
                in->r_addend = in32.r_addend;
            } else {
                in->r_offset = rev_32word(in32.r_offset);
                revinplc_32word(&in32.r_info);
                in->r_info = ELF64_R_INFO(ELF32_R_SYM(in32.r_info),
                                          ELF32_R_TYPE(in32.r_info));
                in->r_addend = rev_32word(in32.r_addend);
            }
        }
    }
    return r;
}
Exemplo n.º 3
0
void Elf64Output::sort_symtab() {
    // With ELF, the local symbols must come first in the symbol table.
    // Annoying, but true.  As a result, this function is necessary to 
    // reorder the symbols with the local ones first.

    std::vector<Elf64_Sym> symtmp;
    std::vector<size_t> redirect(sym_.size());
    // Mapping from old => new position of the symbol in the symbol table.
    for (int i = 0; i < sym_.size(); ++i) {
        if (ELF64_ST_BIND(sym_[i].st_info) == STB_LOCAL) {
            redirect[i] = symtmp.size(); 
            symtmp.push_back(sym_[i]);
        }
    } 
    local_syms_ = symtmp.size();
    for (int i = 0; i < sym_.size(); ++i) {
        if (ELF64_ST_BIND(sym_[i].st_info) == STB_GLOBAL) {
            redirect[i] = symtmp.size();
            symtmp.push_back(sym_[i]);
        }
    }
    for (int i = 0; i < text_reloc_.size(); ++i) {
        Elf64_Word type = ELF64_R_TYPE(text_reloc_[i].r_info);
        Elf64_Word sym = redirect[ELF64_R_SYM(text_reloc_[i].r_info)];
        text_reloc_[i].r_info = ELF64_R_INFO(sym, type);
    }
    for (int i = 0; i < data_reloc_.size(); ++i) {
        Elf64_Word type = ELF64_R_TYPE(data_reloc_[i].r_info);
        Elf64_Word sym = redirect[ELF64_R_SYM(data_reloc_[i].r_info)];
        assert(sym<sym_.size());
        data_reloc_[i].r_info = ELF64_R_INFO(sym, type);
    }
    sym_ = symtmp;
}
Exemplo n.º 4
0
GElf_Rel *
gelf_getrel(Elf_Data *ed, int ndx, GElf_Rel *dst)
{
	int ec;
	Elf *e;
	size_t msz;
	Elf_Scn *scn;
	uint32_t sh_type;
	Elf32_Rel *rel32;
	Elf64_Rel *rel64;
	struct _Libelf_Data *d;

	d = (struct _Libelf_Data *) ed;

	if (d == NULL || ndx < 0 || dst == NULL ||
	    (scn = d->d_scn) == NULL ||
	    (e = scn->s_elf) == NULL) {
		LIBELF_SET_ERROR(ARGUMENT, 0);
		return (NULL);
	}

	ec = e->e_class;
	assert(ec == ELFCLASS32 || ec == ELFCLASS64);

	if (ec == ELFCLASS32)
		sh_type = scn->s_shdr.s_shdr32.sh_type;
	else
		sh_type = scn->s_shdr.s_shdr64.sh_type;

	if (_libelf_xlate_shtype(sh_type) != ELF_T_REL) {
		LIBELF_SET_ERROR(ARGUMENT, 0);
		return (NULL);
	}

	msz = _libelf_msize(ELF_T_REL, ec, e->e_version);

	assert(msz > 0);

	if (msz * ndx >= d->d_data.d_size) {
		LIBELF_SET_ERROR(ARGUMENT, 0);
		return (NULL);
	}

	if (ec == ELFCLASS32) {
		rel32 = (Elf32_Rel *) d->d_data.d_buf + ndx;

		dst->r_offset = (Elf64_Addr) rel32->r_offset;
		dst->r_info   = ELF64_R_INFO(
		    (Elf64_Xword) ELF32_R_SYM(rel32->r_info),
		    ELF32_R_TYPE(rel32->r_info));

	} else {

		rel64 = (Elf64_Rel *) d->d_data.d_buf + ndx;

		*dst = *rel64;
	}

	return (dst);
}
Exemplo n.º 5
0
void Elf64Output::ref(String* label, RelocType rtype) {
    // Refer to a symbol by name at the current text/data output location.
    // This function adds an entry to the relocation table.  The size can be
    // either 4 or 8 bytes.  A 4-byte entry indicates the instruction uses
    // RIP-relative addressing for x64.
    std::map<String::Ptr,size_t>::iterator i = symbol_.find(label);
    size_t symnum = 0;
    if (i == symbol_.end()) {
        symbol_.insert(std::make_pair(label, sym_.size()));
        sym_.resize(sym_.size()+1);
        Elf64_Sym* const sym = &sym_.back();
        sym->st_name = string_->bytes();
        sym->st_info = ELF64_ST_INFO(STB_GLOBAL, STT_NOTYPE);
        sym->st_other = 0;
        sym->st_shndx = SHN_UNDEF;
        sym->st_value = 0;
        sym->st_size = 0; // Unknown size
        string_->buffer(label->string().c_str(), label->string().size()+1);
        symnum = sym_.size()-1;
    } else {
        symnum = i->second;
    }

    Elf64_Rela reloc;
    if (REF_TEXT == rtype) {
        reloc.r_offset = text_->bytes();
        reloc.r_info = ELF64_R_INFO(symnum, R_X86_64_64);
        reloc.r_addend = 0;
        text_reloc_.push_back(reloc);
    } else if (REF_DATA == rtype || REF_VTABLE == rtype) {
        reloc.r_offset = data_->bytes();
        reloc.r_info = ELF64_R_INFO(symnum, R_X86_64_64);
        reloc.r_addend = 0;
        data_reloc_.push_back(reloc);
    } else if (REF_BRANCH == rtype || REF_CALL == rtype) {
        reloc.r_offset = text_->bytes();
        reloc.r_info = ELF64_R_INFO(symnum, R_X86_64_PC32);
        reloc.r_addend = -sizeof(uint32_t);
        text_reloc_.push_back(reloc);
    } else if (REF_SIGNED == rtype) {
        reloc.r_offset = text_->bytes();
        reloc.r_info = ELF64_R_INFO(symnum, R_X86_64_PC32);
        reloc.r_addend = -sizeof(uint32_t);
        text_reloc_.push_back(reloc);
    } 
}
Exemplo n.º 6
0
	void add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char type, Elf_Sxword addend ) {
		Elf_Xword info;
		if ( elf_file.get_class() == ELFCLASS32 ) {
			info = ELF32_R_INFO( symbol, type );
		} else {
			info = ELF64_R_INFO( symbol, type );
		}
		add_entry( offset, info, addend );
	}
Exemplo n.º 7
0
static void addRel64(elfull o,elfull a,elfull i,elfull r)
{
  if (RELA) {
    struct Rela64Node *rn = mymalloc(sizeof(struct Rela64Node));

    setval(be,rn->r.r_offset,8,o);
    setval(be,rn->r.r_addend,8,a);
    setval(be,rn->r.r_info,8,ELF64_R_INFO(i,r));
    addtail(&relalist,&(rn->n));
  }
  else {
    struct Rel64Node *rn = mymalloc(sizeof(struct Rel64Node));

    setval(be,rn->r.r_offset,8,o);
    setval(be,rn->r.r_info,8,ELF64_R_INFO(i,r));
    addtail(&relalist,&(rn->n));
  }
}
Exemplo n.º 8
0
static void
addgotsym(Sym *s)
{
	Sym *got, *rela;

	if(s->got >= 0)
		return;

	adddynsym(s);
	got = lookup(".got", 0);
	s->got = got->size;
	adduint64(got, 0);

	if(iself) {
		rela = lookup(".rela", 0);
		addaddrplus(rela, got, s->got);
		adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT));
		adduint64(rela, 0);
	} else if(HEADTYPE == Hdarwin) {
		adduint32(lookup(".linkedit.got", 0), s->dynid);
	} else {
		diag("addgotsym: unsupported binary format");
	}
}
Exemplo n.º 9
0
static void
addpltsym(Sym *s)
{
	if(s->plt >= 0)
		return;
	
	adddynsym(s);
	
	if(iself) {
		Sym *plt, *got, *rela;

		plt = lookup(".plt", 0);
		got = lookup(".got.plt", 0);
		rela = lookup(".rela.plt", 0);
		if(plt->size == 0)
			elfsetupplt();
		
		// jmpq *got+size(IP)
		adduint8(plt, 0xff);
		adduint8(plt, 0x25);
		addpcrelplus(plt, got, got->size);
	
		// add to got: pointer to current pos in plt
		addaddrplus(got, plt, plt->size);
		
		// pushq $x
		adduint8(plt, 0x68);
		adduint32(plt, (got->size-24-8)/8);
		
		// jmpq .plt
		adduint8(plt, 0xe9);
		adduint32(plt, -(plt->size+4));
		
		// rela
		addaddrplus(rela, got, got->size-8);
		adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT));
		adduint64(rela, 0);
		
		s->plt = plt->size - 16;
	} else if(HEADTYPE == Hdarwin) {
		// To do lazy symbol lookup right, we're supposed
		// to tell the dynamic loader which library each 
		// symbol comes from and format the link info
		// section just so.  I'm too lazy (ha!) to do that
		// so for now we'll just use non-lazy pointers,
		// which don't need to be told which library to use.
		//
		// http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
		// has details about what we're avoiding.

		Sym *plt;
		
		addgotsym(s);
		plt = lookup(".plt", 0);

		adduint32(lookup(".linkedit.plt", 0), s->dynid);

		// jmpq *got+size(IP)
		s->plt = plt->size;

		adduint8(plt, 0xff);
		adduint8(plt, 0x25);
		addpcrelplus(plt, lookup(".got", 0), s->got);
	} else {
		diag("addpltsym: unsupported binary format");
	}
}
Exemplo n.º 10
0
void
adddynrel(Sym *s, Reloc *r)
{
	Sym *targ, *rela, *got;
	
	targ = r->sym;
	cursym = s;

	switch(r->type) {
	default:
		if(r->type >= 256) {
			diag("unexpected relocation type %d", r->type);
			return;
		}
		break;

	// Handle relocations found in ELF object files.
	case 256 + R_X86_64_PC32:
		if(targ->dynimpname != nil && !targ->dynexport)
			diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ->name);
		if(targ->type == 0 || targ->type == SXREF)
			diag("unknown symbol %s in pcrel", targ->name);
		r->type = D_PCREL;
		r->add += 4;
		return;
	
	case 256 + R_X86_64_PLT32:
		r->type = D_PCREL;
		r->add += 4;
		if(targ->dynimpname != nil && !targ->dynexport) {
			addpltsym(targ);
			r->sym = lookup(".plt", 0);
			r->add += targ->plt;
		}
		return;
	
	case 256 + R_X86_64_GOTPCREL:
		if(targ->dynimpname == nil || targ->dynexport) {
			// have symbol
			if(r->off >= 2 && s->p[r->off-2] == 0x8b) {
				// turn MOVQ of GOT entry into LEAQ of symbol itself
				s->p[r->off-2] = 0x8d;
				r->type = D_PCREL;
				r->add += 4;
				return;
			}
			// fall back to using GOT and hope for the best (CMOV*)
			// TODO: just needs relocation, no need to put in .dynsym
			targ->dynimpname = targ->name;
		}
		addgotsym(targ);
		r->type = D_PCREL;
		r->sym = lookup(".got", 0);
		r->add += 4;
		r->add += targ->got;
		return;
	
	case 256 + R_X86_64_64:
		if(targ->dynimpname != nil && !targ->dynexport)
			diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name);
		r->type = D_ADDR;
		return;
	
	// Handle relocations found in Mach-O object files.
	case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 0:
	case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 0:
	case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0:
		// TODO: What is the difference between all these?
		r->type = D_ADDR;
		if(targ->dynimpname != nil && !targ->dynexport)
			diag("unexpected reloc for dynamic symbol %s", targ->name);
		return;

	case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
		if(targ->dynimpname != nil && !targ->dynexport) {
			addpltsym(targ);
			r->sym = lookup(".plt", 0);
			r->add = targ->plt;
			r->type = D_PCREL;
			return;
		}
		// fall through
	case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 1:
	case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 1:
	case 512 + MACHO_X86_64_RELOC_SIGNED_1*2 + 1:
	case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1:
	case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
		r->type = D_PCREL;
		if(targ->dynimpname != nil && !targ->dynexport)
			diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name);
		return;

	case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
		if(targ->dynimpname == nil || targ->dynexport) {
			// have symbol
			// turn MOVQ of GOT entry into LEAQ of symbol itself
			if(r->off < 2 || s->p[r->off-2] != 0x8b) {
				diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name);
				return;
			}
			s->p[r->off-2] = 0x8d;
			r->type = D_PCREL;
			return;
		}
		// fall through
	case 512 + MACHO_X86_64_RELOC_GOT*2 + 1:
		if(targ->dynimpname == nil || targ->dynexport)
			diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
		addgotsym(targ);
		r->type = D_PCREL;
		r->sym = lookup(".got", 0);
		r->add += targ->got;
		return;
	}
	
	// Handle references to ELF symbols from our own object files.
	if(targ->dynimpname == nil || targ->dynexport)
		return;

	switch(r->type) {
	case D_PCREL:
		addpltsym(targ);
		r->sym = lookup(".plt", 0);
		r->add = targ->plt;
		return;
	
	case D_ADDR:
		if(s->type != SDATA)
			break;
		if(iself) {
			adddynsym(targ);
			rela = lookup(".rela", 0);
			addaddrplus(rela, s, r->off);
			if(r->siz == 8)
				adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_64));
			else
				adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_32));
			adduint64(rela, r->add);
			r->type = 256;	// ignore during relocsym
			return;
		}
		if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) {
			// Mach-O relocations are a royal pain to lay out.
			// They use a compact stateful bytecode representation
			// that is too much bother to deal with.
			// Instead, interpret the C declaration
			//	void *_Cvar_stderr = &stderr;
			// as making _Cvar_stderr the name of a GOT entry
			// for stderr.  This is separate from the usual GOT entry,
			// just in case the C code assigns to the variable,
			// and of course it only works for single pointers,
			// but we only need to support cgo and that's all it needs.
			adddynsym(targ);
			got = lookup(".got", 0);
			s->type = got->type | SSUB;
			s->outer = got;
			s->sub = got->sub;
			got->sub = s;
			s->value = got->size;
			adduint64(got, 0);
			adduint32(lookup(".linkedit.got", 0), targ->dynid);
			r->type = 256;	// ignore during relocsym
			return;
		}
		break;
	}
	
	cursym = s;
	diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
}
Exemplo n.º 11
0
static int
reloc_read(const struct buffer *in, struct parsed_elf *pelf,
           struct xdr *xdr, int bit64)
{
	struct buffer b;
	Elf64_Word i;
	Elf64_Ehdr *ehdr;

	ehdr = &pelf->ehdr;
	pelf->relocs = calloc(ehdr->e_shnum, sizeof(Elf64_Rela *));

	/* Allocate array for each section that contains relocation entries. */
	for (i = 0; i < ehdr->e_shnum; i++) {
		Elf64_Shdr *shdr;
		Elf64_Rela *rela;
		Elf64_Xword j;
		Elf64_Xword nrelocs;
		int is_rela;

		shdr = &pelf->shdr[i];

		/* Only process REL and RELA sections. */
		if (shdr->sh_type != SHT_REL && shdr->sh_type != SHT_RELA)
			continue;

		DEBUG("Checking relocation section %u\n", i);

		/* Ensure the section that relocations apply is a valid. */
		if (shdr->sh_info >= ehdr->e_shnum ||
		    shdr->sh_info == SHN_UNDEF) {
			ERROR("Relocations apply to an invalid section: %u\n",
			      shdr[i].sh_info);
			return -1;
		}

		is_rela = shdr->sh_type == SHT_RELA;

		/* Determine the number relocations in this section. */
		nrelocs = shdr->sh_size / shdr->sh_entsize;

		pelf->relocs[i] = calloc(nrelocs, sizeof(Elf64_Rela));

		buffer_splice(&b, in, shdr->sh_offset, shdr->sh_size);
		if (check_size(in, shdr->sh_offset, buffer_size(&b),
		               "relocation section")) {
			ERROR("Relocation section %u failed.\n", i);
			return -1;
		}

		rela = pelf->relocs[i];
		for (j = 0; j < nrelocs; j++) {
			if (bit64) {
				rela->r_offset = xdr->get64(&b);
				rela->r_info = xdr->get64(&b);
				if (is_rela)
					rela->r_addend = xdr->get64(&b);
			} else {
				uint32_t r_info;

				rela->r_offset = xdr->get32(&b);
				r_info = xdr->get32(&b);
				rela->r_info = ELF64_R_INFO(ELF32_R_SYM(r_info),
				                          ELF32_R_TYPE(r_info));
				if (is_rela)
					rela->r_addend = xdr->get32(&b);
			}
			rela++;
		}
	}

	return 0;
}
void RelocationAddend64::setSymbolInfo(uint32_t sym){
    entry.r_info = ELF64_R_INFO(sym, getType());    
}