void adddynrela(Sym *rela, Sym *s, Reloc *r) { addaddrplus(rela, s, r->off); adduint64(rela, R_X86_64_RELATIVE); addaddrplus(rela, r->sym, r->add); // Addend }
void elfsetupplt(void) { Sym *plt, *got; plt = lookup(".plt", 0); got = lookup(".got.plt", 0); if(plt->size == 0) { // pushl got+4 adduint8(plt, 0xff); adduint8(plt, 0x35); addaddrplus(plt, got, 4); // jmp *got+8 adduint8(plt, 0xff); adduint8(plt, 0x25); addaddrplus(plt, got, 8); // zero pad adduint32(plt, 0); // assume got->size == 0 too addaddrplus(got, lookup(".dynamic", 0), 0); adduint32(got, 0); adduint32(got, 0); } }
static void addpltsym(Sym *s) { Sym *plt, *got, *rel; if(s->plt >= 0) return; adddynsym(s); if(iself) { plt = lookup(".plt", 0); got = lookup(".got.plt", 0); rel = lookup(".rel.plt", 0); if(plt->size == 0) elfsetupplt(); // jmpq *got+size adduint8(plt, 0xff); adduint8(plt, 0x25); addaddrplus(plt, got, got->size); // add to got: pointer to current pos in plt addaddrplus(got, plt, plt->size); // pushl $x adduint8(plt, 0x68); adduint32(plt, rel->size); // jmp .plt adduint8(plt, 0xe9); adduint32(plt, -(plt->size+4)); // rel addaddrplus(rel, got, got->size-4); adduint32(rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT)); s->plt = plt->size - 16; } else if(HEADTYPE == Hdarwin) { // Same laziness as in 6l. Sym *plt; plt = lookup(".plt", 0); addgotsym(s); adduint32(lookup(".linkedit.plt", 0), s->dynid); // jmpq *got+size(IP) s->plt = plt->size; adduint8(plt, 0xff); adduint8(plt, 0x25); addaddrplus(plt, lookup(".got", 0), s->got); } else { diag("addpltsym: unsupported binary format"); } }
void elfsetupplt(void) { Sym *plt, *got; plt = lookup(".plt", 0); got = lookup(".got.plt", 0); if(plt->size == 0) { // pushq got+8(IP) adduint8(plt, 0xff); adduint8(plt, 0x35); addpcrelplus(plt, got, 8); // jmpq got+16(IP) adduint8(plt, 0xff); adduint8(plt, 0x25); addpcrelplus(plt, got, 16); // nopl 0(AX) adduint32(plt, 0x00401f0f); // assume got->size == 0 too addaddrplus(got, lookup(".dynamic", 0), 0); adduint64(got, 0); adduint64(got, 0); } }
static void addgotsym(Sym *s) { Sym *got, *rel; if(s->got >= 0) return; adddynsym(s); got = lookup(".got", 0); s->got = got->size; adduint32(got, 0); if(iself) { rel = lookup(".rel", 0); addaddrplus(rel, got, s->got); adduint32(rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT)); } else if(HEADTYPE == Hdarwin) { adduint32(lookup(".linkedit.got", 0), s->dynid); } else { diag("addgotsym: unsupported binary format"); } }
static void addgotsym(LSym *s) { LSym *got, *rela; if(s->got >= 0) return; adddynsym(ctxt, s); got = linklookup(ctxt, ".got", 0); s->got = got->size; adduint64(ctxt, got, 0); if(iself) { rela = linklookup(ctxt, ".rela", 0); addaddrplus(ctxt, rela, got, s->got); adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT)); adduint64(ctxt, rela, 0); } else if(HEADTYPE == Hdarwin) { adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid); } else { diag("addgotsym: unsupported binary format"); } }
vlong addaddr(Sym *s, Sym *t) { return addaddrplus(s, t, 0); }
void adddynrel(Sym *s, Reloc *r) { Sym *targ, *rel, *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_386_PC32: if(targ->type == SDYNIMPORT) diag("unexpected R_386_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_386_PLT32: r->type = D_PCREL; r->add += 4; if(targ->type == SDYNIMPORT) { addpltsym(targ); r->sym = lookup(".plt", 0); r->add += targ->plt; } return; case 256 + R_386_GOT32: if(targ->type != SDYNIMPORT) { // have symbol // turn MOVL of GOT entry into LEAL of symbol itself if(r->off < 2 || s->p[r->off-2] != 0x8b) { diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); return; } s->p[r->off-2] = 0x8d; r->type = D_GOTOFF; return; } addgotsym(targ); r->type = D_CONST; // write r->add during relocsym r->sym = S; r->add += targ->got; return; case 256 + R_386_GOTOFF: r->type = D_GOTOFF; return; case 256 + R_386_GOTPC: r->type = D_PCREL; r->sym = lookup(".got", 0); r->add += 4; return; case 256 + R_386_32: if(targ->type == SDYNIMPORT) diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name); r->type = D_ADDR; return; case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0: r->type = D_ADDR; if(targ->type == SDYNIMPORT) diag("unexpected reloc for dynamic symbol %s", targ->name); return; case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1: if(targ->type == SDYNIMPORT) { addpltsym(targ); r->sym = lookup(".plt", 0); r->add = targ->plt; r->type = D_PCREL; return; } r->type = D_PCREL; return; case 512 + MACHO_FAKE_GOTPCREL: if(targ->type != SDYNIMPORT) { // have symbol // turn MOVL of GOT entry into LEAL of symbol itself if(r->off < 2 || s->p[r->off-2] != 0x8b) { diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); return; } s->p[r->off-2] = 0x8d; r->type = D_PCREL; return; } addgotsym(targ); r->sym = lookup(".got", 0); r->add += targ->got; r->type = D_PCREL; return; } // Handle references to ELF symbols from our own object files. if(targ->type != SDYNIMPORT) 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); rel = lookup(".rel", 0); addaddrplus(rel, s, r->off); adduint32(rel, ELF32_R_INFO(targ->dynid, R_386_32)); r->type = D_CONST; // write r->add during relocsym r->sym = S; 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; adduint32(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); }
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"); } }
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); }