mirror of https://github.com/golang/go.git
cmd/5l, cmd/ld: dynamic linking library support
Part 1 of CL 5601044 (cgo: Linux/ARM support)
Limitation: doesn't support thumb library yet.
R=golang-dev, dave, rsc
CC=golang-dev
https://golang.org/cl/5991065
This commit is contained in:
parent
c44a22cc49
commit
452a9e452b
|
|
@ -254,6 +254,12 @@ enum as
|
|||
/* internal only */
|
||||
#define D_SIZE (D_NONE+40)
|
||||
#define D_PCREL (D_NONE+41)
|
||||
#define D_GOTOFF (D_NONE+42) // R_ARM_GOTOFF
|
||||
#define D_PLT0 (D_NONE+43) // R_ARM_PLT32, 1st inst: add ip, pc, #0xNN00000
|
||||
#define D_PLT1 (D_NONE+44) // R_ARM_PLT32, 2nd inst: add ip, ip, #0xNN000
|
||||
#define D_PLT2 (D_NONE+45) // R_ARM_PLT32, 3rd inst: ldr pc, [ip, #0xNNN]!
|
||||
#define D_PLT32 (D_NONE+46) // R_ARM_PLT32, bl xxxxx
|
||||
#define D_CALL (D_NONE+47) // R_ARM_CALL, bl xxxxx
|
||||
|
||||
/*
|
||||
* this is the ranlib header
|
||||
|
|
|
|||
411
src/cmd/5l/asm.c
411
src/cmd/5l/asm.c
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
static Prog *PP;
|
||||
|
||||
char linuxdynld[] = "/lib/ld-linux.so.2";
|
||||
char linuxdynld[] = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI
|
||||
|
||||
int32
|
||||
entryvalue(void)
|
||||
|
|
@ -73,6 +73,8 @@ enum {
|
|||
ElfStrShstrtab,
|
||||
ElfStrRelPlt,
|
||||
ElfStrPlt,
|
||||
ElfStrGnuVersion,
|
||||
ElfStrGnuVersionR,
|
||||
ElfStrNoteNetbsdIdent,
|
||||
ElfStrNoPtrData,
|
||||
ElfStrNoPtrBss,
|
||||
|
|
@ -103,36 +105,354 @@ needlib(char *name)
|
|||
|
||||
int nelfsym = 1;
|
||||
|
||||
void
|
||||
adddynrel(Sym *s, Reloc *r)
|
||||
static void addpltsym(Sym*);
|
||||
static void addgotsym(Sym*);
|
||||
static void addgotsyminternal(Sym*);
|
||||
|
||||
// Preserve highest 8 bits of a, and do addition to lower 24-bit
|
||||
// of a and b; used to adjust ARM branch intruction's target
|
||||
static int32
|
||||
braddoff(int32 a, int32 b)
|
||||
{
|
||||
USED(s);
|
||||
USED(r);
|
||||
diag("adddynrel: unsupported binary format");
|
||||
return (((uint32)a) & 0xff000000U) | (0x00ffffffU & (uint32)(a + b));
|
||||
}
|
||||
|
||||
void
|
||||
adddynsym(Sym *s)
|
||||
adddynrel(Sym *s, Reloc *r)
|
||||
{
|
||||
USED(s);
|
||||
diag("adddynsym: not implemented");
|
||||
Sym *targ, *rel;
|
||||
|
||||
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_ARM_PLT32:
|
||||
r->type = D_PLT32;
|
||||
if(targ->dynimpname != nil && !targ->dynexport) {
|
||||
addpltsym(targ);
|
||||
r->sym = lookup(".plt", 0);
|
||||
r->add = braddoff(r->add, targ->plt / 4);
|
||||
}
|
||||
return;
|
||||
|
||||
case 256 + R_ARM_THM_PC22: // R_ARM_THM_CALL
|
||||
diag("R_ARM_THM_CALL, are you using -marm?");
|
||||
errorexit();
|
||||
return;
|
||||
|
||||
case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL
|
||||
if(targ->dynimpname == nil || targ->dynexport) {
|
||||
addgotsyminternal(targ);
|
||||
} else {
|
||||
addgotsym(targ);
|
||||
}
|
||||
r->type = D_CONST; // write r->add during relocsym
|
||||
r->sym = S;
|
||||
r->add += targ->got;
|
||||
return;
|
||||
|
||||
case 256 + R_ARM_GOTOFF: // R_ARM_GOTOFF32
|
||||
r->type = D_GOTOFF;
|
||||
return;
|
||||
|
||||
case 256 + R_ARM_GOTPC: // R_ARM_BASE_PREL
|
||||
r->type = D_PCREL;
|
||||
r->sym = lookup(".got", 0);
|
||||
r->add += 4;
|
||||
return;
|
||||
|
||||
case 256 + R_ARM_CALL:
|
||||
r->type = D_CALL;
|
||||
r->add += 0;
|
||||
return;
|
||||
|
||||
case 256 + R_ARM_REL32: // R_ARM_REL32
|
||||
r->type = D_PCREL;
|
||||
r->add += 4;
|
||||
return;
|
||||
|
||||
case 256 + R_ARM_ABS32:
|
||||
if(targ->dynimpname != nil && !targ->dynexport)
|
||||
diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ->name);
|
||||
r->type = D_ADDR;
|
||||
return;
|
||||
|
||||
case 256 + R_ARM_V4BX:
|
||||
// we can just ignore this, because we are targeting ARM V5+ anyway
|
||||
if(r->sym) {
|
||||
// R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
|
||||
r->sym->type = 0;
|
||||
}
|
||||
r->sym = S;
|
||||
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);
|
||||
rel = lookup(".rel", 0);
|
||||
addaddrplus(rel, s, r->off);
|
||||
adduint32(rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a S + A dynmic reloc
|
||||
r->type = D_CONST; // write r->add during relocsym
|
||||
r->sym = S;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
cursym = s;
|
||||
diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
|
||||
}
|
||||
|
||||
static void
|
||||
elfsetupplt(void)
|
||||
{
|
||||
// TODO
|
||||
Sym *plt, *got;
|
||||
|
||||
plt = lookup(".plt", 0);
|
||||
got = lookup(".got.plt", 0);
|
||||
if(plt->size == 0) {
|
||||
// str lr, [sp, #-4]!
|
||||
adduint32(plt, 0xe52de004);
|
||||
// ldr lr, [pc, #4]
|
||||
adduint32(plt, 0xe59fe004);
|
||||
// add lr, pc, lr
|
||||
adduint32(plt, 0xe08fe00e);
|
||||
// ldr pc, [lr, #8]!
|
||||
adduint32(plt, 0xe5bef008);
|
||||
// .word &GLOBAL_OFFSET_TABLE[0] - .
|
||||
addpcrelplus(plt, got, 4);
|
||||
|
||||
// the first .plt entry requires 3 .plt.got entries
|
||||
adduint32(got, 0);
|
||||
adduint32(got, 0);
|
||||
adduint32(got, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
archreloc(Reloc *r, Sym *s, vlong *val)
|
||||
{
|
||||
USED(r);
|
||||
USED(s);
|
||||
USED(val);
|
||||
switch(r->type) {
|
||||
case D_CONST:
|
||||
*val = r->add;
|
||||
return 0;
|
||||
case D_GOTOFF:
|
||||
*val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
|
||||
return 0;
|
||||
// The following three arch specific relocations are only for generation of
|
||||
// Linux/ARM ELF's PLT entry (3 assembler instruction)
|
||||
case D_PLT0: // add ip, pc, #0xXX00000
|
||||
if (symaddr(lookup(".got.plt", 0)) < symaddr(lookup(".plt", 0)))
|
||||
diag(".got.plt should be placed after .plt section.");
|
||||
*val = 0xe28fc600U +
|
||||
(0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add) >> 20));
|
||||
return 0;
|
||||
case D_PLT1: // add ip, ip, #0xYY000
|
||||
*val = 0xe28cca00U +
|
||||
(0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 4) >> 12));
|
||||
return 0;
|
||||
case D_PLT2: // ldr pc, [ip, #0xZZZ]!
|
||||
*val = 0xe5bcf000U +
|
||||
(0xfff & (uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 8));
|
||||
return 0;
|
||||
case D_PLT32: // bl XXXXXX or b YYYYYY in R_ARM_PLT32
|
||||
*val = (0xff000000U & (uint32)r->add) +
|
||||
(0xffffff & (uint32)((symaddr(r->sym) + (0xffffffU & (uint32)r->add) * 4) - (s->value + r->off)) / 4);
|
||||
return 0;
|
||||
case D_CALL: // bl XXXXXX
|
||||
*val = braddoff(0xeb000000U, (0xffffff & (uint32)((symaddr(r->sym) + ((uint32)r->add) * 4 - (s->value + r->off)) / 4)));
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static Reloc *
|
||||
addpltreloc(Sym *plt, Sym *got, Sym *sym, int typ)
|
||||
{
|
||||
Reloc *r;
|
||||
r = addrel(plt);
|
||||
r->sym = got;
|
||||
r->off = plt->size;
|
||||
r->siz = 4;
|
||||
r->type = typ;
|
||||
r->add = sym->got - 8;
|
||||
|
||||
plt->reachable = 1;
|
||||
plt->size += 4;
|
||||
symgrow(plt, plt->size);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
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", 0);
|
||||
if(plt->size == 0)
|
||||
elfsetupplt();
|
||||
|
||||
// .got entry
|
||||
s->got = got->size;
|
||||
adduint32(got, 0);
|
||||
|
||||
// .plt entry, this depends on the .got entry
|
||||
s->plt = plt->size;
|
||||
addpltreloc(plt, got, s, D_PLT0); // add lr, pc, #0xXX00000
|
||||
addpltreloc(plt, got, s, D_PLT1); // add lr, lr, #0xYY000
|
||||
addpltreloc(plt, got, s, D_PLT2); // ldr pc, [lr, #0xZZZ]!
|
||||
|
||||
// rel
|
||||
addaddrplus(rel, got, s->got);
|
||||
adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT));
|
||||
} else {
|
||||
diag("addpltsym: unsupported binary format");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
addgotsyminternal(Sym *s)
|
||||
{
|
||||
Sym *got;
|
||||
|
||||
if(s->got >= 0)
|
||||
return;
|
||||
|
||||
got = lookup(".got", 0);
|
||||
s->got = got->size;
|
||||
|
||||
addaddrplus(got, s, 0);
|
||||
|
||||
if(iself) {
|
||||
;
|
||||
} else {
|
||||
diag("addgotsyminternal: unsupported binary format");
|
||||
}
|
||||
}
|
||||
|
||||
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_ARM_GLOB_DAT));
|
||||
} else {
|
||||
diag("addgotsym: unsupported binary format");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
adddynsym(Sym *s)
|
||||
{
|
||||
Sym *d;
|
||||
int t;
|
||||
char *name;
|
||||
|
||||
if(s->dynid >= 0)
|
||||
return;
|
||||
|
||||
if(s->dynimpname == nil) {
|
||||
s->dynimpname = s->name;
|
||||
//diag("adddynsym: no dynamic name for %s", s->name);
|
||||
}
|
||||
|
||||
if(iself) {
|
||||
s->dynid = nelfsym++;
|
||||
|
||||
d = lookup(".dynsym", 0);
|
||||
|
||||
/* name */
|
||||
name = s->dynimpname;
|
||||
if(name == nil)
|
||||
name = s->name;
|
||||
adduint32(d, addstring(lookup(".dynstr", 0), name));
|
||||
|
||||
/* value */
|
||||
if(s->type == SDYNIMPORT)
|
||||
adduint32(d, 0);
|
||||
else
|
||||
addaddr(d, s);
|
||||
|
||||
/* size */
|
||||
adduint32(d, 0);
|
||||
|
||||
/* type */
|
||||
t = STB_GLOBAL << 4;
|
||||
if(s->dynexport && s->type == STEXT)
|
||||
t |= STT_FUNC;
|
||||
else
|
||||
t |= STT_OBJECT;
|
||||
adduint8(d, t);
|
||||
adduint8(d, 0);
|
||||
|
||||
/* shndx */
|
||||
if(!s->dynexport && s->dynimpname != nil)
|
||||
adduint16(d, SHN_UNDEF);
|
||||
else {
|
||||
switch(s->type) {
|
||||
default:
|
||||
case STEXT:
|
||||
t = 11;
|
||||
break;
|
||||
case SRODATA:
|
||||
t = 12;
|
||||
break;
|
||||
case SDATA:
|
||||
t = 13;
|
||||
break;
|
||||
case SBSS:
|
||||
t = 14;
|
||||
break;
|
||||
}
|
||||
adduint16(d, t);
|
||||
}
|
||||
} else {
|
||||
diag("adddynsym: unsupported binary format");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
adddynlib(char *lib)
|
||||
{
|
||||
|
|
@ -175,7 +495,7 @@ doelf(void)
|
|||
addstring(shstrtab, ".rodata");
|
||||
addstring(shstrtab, ".gosymtab");
|
||||
addstring(shstrtab, ".gopclntab");
|
||||
if(!debug['s']) {
|
||||
if(!debug['s']) {
|
||||
elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
|
||||
elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
|
||||
}
|
||||
|
|
@ -192,17 +512,19 @@ doelf(void)
|
|||
elfstr[ElfStrRel] = addstring(shstrtab, ".rel");
|
||||
elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt");
|
||||
elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
|
||||
elfstr[ElfStrGnuVersion] = addstring(shstrtab, ".gnu.version");
|
||||
elfstr[ElfStrGnuVersionR] = addstring(shstrtab, ".gnu.version_r");
|
||||
|
||||
/* dynamic symbol table - first entry all zeros */
|
||||
s = lookup(".dynsym", 0);
|
||||
s->type = SELFROSECT;
|
||||
s->reachable = 1;
|
||||
s->value += ELF32SYMSIZE;
|
||||
s->size += ELF32SYMSIZE;
|
||||
|
||||
/* dynamic string table */
|
||||
s = lookup(".dynstr", 0);
|
||||
s->type = SELFROSECT;
|
||||
s->reachable = 1;
|
||||
s->type = SELFROSECT;
|
||||
if(s->size == 0)
|
||||
addstring(s, "");
|
||||
dynstr = s;
|
||||
|
|
@ -234,7 +556,15 @@ doelf(void)
|
|||
s = lookup(".rel.plt", 0);
|
||||
s->reachable = 1;
|
||||
s->type = SELFROSECT;
|
||||
|
||||
|
||||
s = lookup(".gnu.version", 0);
|
||||
s->reachable = 1;
|
||||
s->type = SELFROSECT;
|
||||
|
||||
s = lookup(".gnu.version_r", 0);
|
||||
s->reachable = 1;
|
||||
s->type = SELFROSECT;
|
||||
|
||||
elfsetupplt();
|
||||
|
||||
/* define dynamic elf table */
|
||||
|
|
@ -259,8 +589,9 @@ doelf(void)
|
|||
elfwritedynent(s, DT_PLTREL, DT_REL);
|
||||
elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0));
|
||||
elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0));
|
||||
|
||||
elfwritedynent(s, DT_DEBUG, 0);
|
||||
elfwritedynent(s, DT_NULL, 0);
|
||||
// elfdynhash will finish it
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -335,7 +666,7 @@ asmb(void)
|
|||
/* !debug['d'] causes extra sections before the .text section */
|
||||
elftextsh = 2;
|
||||
if(!debug['d']) {
|
||||
elftextsh += 10;
|
||||
elftextsh += 9;
|
||||
if(elfverneed)
|
||||
elftextsh += 2;
|
||||
}
|
||||
|
|
@ -520,12 +851,13 @@ asmb(void)
|
|||
/* Dynamic linking sections */
|
||||
if(!debug['d']) { /* -d suppresses dynamic loader format */
|
||||
/* S headers for dynamic linking */
|
||||
sh = newElfShdr(elfstr[ElfStrGot]);
|
||||
// ARM ELF needs .plt to be placed before .got
|
||||
sh = newElfShdr(elfstr[ElfStrPlt]);
|
||||
sh->type = SHT_PROGBITS;
|
||||
sh->flags = SHF_ALLOC+SHF_WRITE;
|
||||
sh->flags = SHF_ALLOC+SHF_EXECINSTR;
|
||||
sh->entsize = 4;
|
||||
sh->addralign = 4;
|
||||
shsym(sh, lookup(".got", 0));
|
||||
shsym(sh, lookup(".plt", 0));
|
||||
|
||||
sh = newElfShdr(elfstr[ElfStrGotPlt]);
|
||||
sh->type = SHT_PROGBITS;
|
||||
|
|
@ -534,6 +866,13 @@ asmb(void)
|
|||
sh->addralign = 4;
|
||||
shsym(sh, lookup(".got.plt", 0));
|
||||
|
||||
sh = newElfShdr(elfstr[ElfStrGot]);
|
||||
sh->type = SHT_PROGBITS;
|
||||
sh->flags = SHF_ALLOC+SHF_WRITE;
|
||||
sh->entsize = 4;
|
||||
sh->addralign = 4;
|
||||
shsym(sh, lookup(".got", 0));
|
||||
|
||||
dynsym = eh->shnum;
|
||||
sh = newElfShdr(elfstr[ElfStrDynsym]);
|
||||
sh->type = SHT_DYNSYM;
|
||||
|
|
@ -550,6 +889,24 @@ asmb(void)
|
|||
sh->addralign = 1;
|
||||
shsym(sh, lookup(".dynstr", 0));
|
||||
|
||||
if(elfverneed) {
|
||||
sh = newElfShdr(elfstr[ElfStrGnuVersion]);
|
||||
sh->type = SHT_GNU_VERSYM;
|
||||
sh->flags = SHF_ALLOC;
|
||||
sh->addralign = 2;
|
||||
sh->link = dynsym;
|
||||
sh->entsize = 2;
|
||||
shsym(sh, lookup(".gnu.version", 0));
|
||||
|
||||
sh = newElfShdr(elfstr[ElfStrGnuVersionR]);
|
||||
sh->type = SHT_GNU_VERNEED;
|
||||
sh->flags = SHF_ALLOC;
|
||||
sh->addralign = 4;
|
||||
sh->info = elfverneed;
|
||||
sh->link = dynsym+1; // dynstr
|
||||
shsym(sh, lookup(".gnu.version_r", 0));
|
||||
}
|
||||
|
||||
sh = newElfShdr(elfstr[ElfStrHash]);
|
||||
sh->type = SHT_HASH;
|
||||
sh->flags = SHF_ALLOC;
|
||||
|
|
@ -574,14 +931,12 @@ asmb(void)
|
|||
sh->addralign = 4;
|
||||
sh->link = dynsym+1; // dynstr
|
||||
shsym(sh, lookup(".dynamic", 0));
|
||||
|
||||
ph = newElfPhdr();
|
||||
ph->type = PT_DYNAMIC;
|
||||
ph->flags = PF_R + PF_W;
|
||||
phsh(ph, sh);
|
||||
|
||||
/*
|
||||
* Thread-local storage segment (really just size).
|
||||
// .tbss (optional) and TLS phdr
|
||||
if(tlsoffset != 0) {
|
||||
ph = newElfPhdr();
|
||||
ph->type = PT_TLS;
|
||||
|
|
@ -589,7 +944,6 @@ asmb(void)
|
|||
ph->memsz = -tlsoffset;
|
||||
ph->align = 4;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
ph = newElfPhdr();
|
||||
|
|
@ -1849,7 +2203,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
|
|||
for(s=hash[h]; s!=S; s=s->hash) {
|
||||
if(s->hide)
|
||||
continue;
|
||||
switch(s->type) {
|
||||
switch(s->type&~SSUB) {
|
||||
case SCONST:
|
||||
case SRODATA:
|
||||
case SDATA:
|
||||
|
|
@ -1882,6 +2236,9 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
|
|||
}
|
||||
|
||||
for(s = textp; s != nil; s = s->next) {
|
||||
if(s->text == nil)
|
||||
continue;
|
||||
|
||||
/* filenames first */
|
||||
for(a=s->autom; a; a=a->link)
|
||||
if(a->type == D_FILE)
|
||||
|
|
|
|||
|
|
@ -303,6 +303,7 @@ EXTERN int version;
|
|||
EXTERN char xcmp[C_GOK+1][C_GOK+1];
|
||||
EXTERN Prog zprg;
|
||||
EXTERN int dtype;
|
||||
EXTERN int tlsoffset;
|
||||
EXTERN int armsize;
|
||||
|
||||
extern char* anames[];
|
||||
|
|
|
|||
|
|
@ -205,7 +205,9 @@ main(int argc, char *argv[])
|
|||
INITRND = 1024;
|
||||
break;
|
||||
case Hlinux: /* arm elf */
|
||||
debug['d'] = 1; // no dynamic linking
|
||||
debug['d'] = 0; // with dynamic linking
|
||||
tlsoffset = -8; // hardcoded number, first 4-byte word for g, and then 4-byte word for m
|
||||
// this number is known to ../../pkg/runtime/cgo/gcc_linux_arm.c
|
||||
elfinit();
|
||||
HEADR = ELFRESERVE;
|
||||
if(INITTEXT == -1)
|
||||
|
|
@ -263,6 +265,8 @@ main(int argc, char *argv[])
|
|||
noops();
|
||||
dostkcheck();
|
||||
span();
|
||||
addexport();
|
||||
// textaddress() functionality is handled in span()
|
||||
pclntab();
|
||||
symtab();
|
||||
dodata();
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ patch(void)
|
|||
s = p->to.sym;
|
||||
if(s->text == nil)
|
||||
continue;
|
||||
switch(s->type) {
|
||||
switch(s->type&~SSUB) {
|
||||
default:
|
||||
diag("undefined: %s", s->name);
|
||||
s->type = STEXT;
|
||||
|
|
@ -231,7 +231,7 @@ patch(void)
|
|||
if(p->to.type != D_BRANCH)
|
||||
continue;
|
||||
c = p->to.offset;
|
||||
for(q = textp->text; q != P;) {
|
||||
for(q = cursym->text; q != P;) {
|
||||
if(c == q->pc)
|
||||
break;
|
||||
if(q->forwd != P && c >= q->forwd->pc)
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ span(void)
|
|||
int32 c, otxt, out[6];
|
||||
Section *sect;
|
||||
uchar *bp;
|
||||
Sym *sub;
|
||||
|
||||
if(debug['v'])
|
||||
Bprint(&bso, "%5.2f span\n", cputime());
|
||||
|
|
@ -100,6 +101,20 @@ span(void)
|
|||
otxt = c;
|
||||
for(cursym = textp; cursym != nil; cursym = cursym->next) {
|
||||
p = cursym->text;
|
||||
if(p == P || p->link == P) { // handle external functions and ELF section symbols
|
||||
if(cursym->type & SSUB)
|
||||
continue;
|
||||
if(cursym->align != 0)
|
||||
c = rnd(c, cursym->align);
|
||||
cursym->value = 0;
|
||||
for(sub = cursym; sub != S; sub = sub->sub) {
|
||||
sub->value += c;
|
||||
for(p = sub->text; p != P; p = p->link)
|
||||
p->pc += sub->value;
|
||||
}
|
||||
c += cursym->size;
|
||||
continue;
|
||||
}
|
||||
p->pc = c;
|
||||
cursym->value = c;
|
||||
|
||||
|
|
@ -160,6 +175,8 @@ span(void)
|
|||
bflag = 0;
|
||||
c = INITTEXT;
|
||||
for(cursym = textp; cursym != nil; cursym = cursym->next) {
|
||||
if(!cursym->text || !cursym->text->link)
|
||||
continue;
|
||||
cursym->value = c;
|
||||
for(p = cursym->text; p != P; p = p->link) {
|
||||
curp = p;
|
||||
|
|
@ -217,6 +234,8 @@ span(void)
|
|||
*/
|
||||
for(cursym = textp; cursym != nil; cursym = cursym->next) {
|
||||
p = cursym->text;
|
||||
if(p == P || p->link == P)
|
||||
continue;
|
||||
autosize = p->to.offset + 4;
|
||||
symgrow(cursym, cursym->size);
|
||||
|
||||
|
|
@ -407,25 +426,9 @@ immhalf(int32 v)
|
|||
int32
|
||||
symaddr(Sym *s)
|
||||
{
|
||||
int32 v;
|
||||
|
||||
v = s->value;
|
||||
switch(s->type) {
|
||||
default:
|
||||
diag("unexpected type %d in symaddr(%s)", s->type, s->name);
|
||||
return 0;
|
||||
|
||||
case STEXT:
|
||||
case SELFROSECT:
|
||||
case SRODATA:
|
||||
case SDATA:
|
||||
case SBSS:
|
||||
case SCONST:
|
||||
case SNOPTRDATA:
|
||||
case SNOPTRBSS:
|
||||
break;
|
||||
}
|
||||
return v;
|
||||
if(!s->reachable)
|
||||
diag("unreachable symbol in symaddr - %s", s->name);
|
||||
return s->value;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ dynrelocsym(Sym *s)
|
|||
}
|
||||
|
||||
for(r=s->r; r<s->r+s->nr; r++)
|
||||
if(r->sym->type == SDYNIMPORT || r->type >= 256)
|
||||
if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256)
|
||||
adddynrel(s, r);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -562,6 +562,8 @@ typedef struct {
|
|||
#define R_ARM_GOTPC 25 /* Add PC-relative GOT table address. */
|
||||
#define R_ARM_GOT32 26 /* Add PC-relative GOT offset. */
|
||||
#define R_ARM_PLT32 27 /* Add PC-relative PLT offset. */
|
||||
#define R_ARM_CALL 28
|
||||
#define R_ARM_V4BX 40
|
||||
#define R_ARM_GNU_VTENTRY 100
|
||||
#define R_ARM_GNU_VTINHERIT 101
|
||||
#define R_ARM_RSBREL32 250
|
||||
|
|
|
|||
|
|
@ -588,14 +588,18 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
|
|||
p += 4;
|
||||
}
|
||||
}
|
||||
if(readsym(obj, info>>32, &sym) < 0)
|
||||
goto bad;
|
||||
if(sym.sym == nil) {
|
||||
werrstr("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d",
|
||||
sect->sym->name, j, (int)(info>>32), sym.name, sym.shndx, sym.type);
|
||||
goto bad;
|
||||
if((info >> 32) == 0) { // absolute relocation, don't bother reading the null symbol
|
||||
rp->sym = S;
|
||||
} else {
|
||||
if(readsym(obj, info>>32, &sym) < 0)
|
||||
goto bad;
|
||||
if(sym.sym == nil) {
|
||||
werrstr("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d",
|
||||
sect->sym->name, j, (int)(info>>32), sym.name, sym.shndx, sym.type);
|
||||
goto bad;
|
||||
}
|
||||
rp->sym = sym.sym;
|
||||
}
|
||||
rp->sym = sym.sym;
|
||||
rp->type = reltype(pn, (uint32)info, &rp->siz);
|
||||
if(rela)
|
||||
rp->add = add;
|
||||
|
|
@ -633,6 +637,8 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
|
|||
}
|
||||
if(sym.shndx >= obj->nsect || sym.shndx == 0)
|
||||
continue;
|
||||
if(thechar == '5' && (strcmp(sym.name, "$a") == 0 || strcmp(sym.name, "$d") == 0)) // binutils for arm generate these mapping symbols, skip these
|
||||
continue;
|
||||
sect = obj->sect+sym.shndx;
|
||||
if(sect->sym == nil) {
|
||||
diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type);
|
||||
|
|
@ -715,6 +721,9 @@ readsym(ElfObj *obj, int i, ElfSym *sym)
|
|||
werrstr("invalid elf symbol index");
|
||||
return -1;
|
||||
}
|
||||
if(i == 0) {
|
||||
diag("readym: read null symbol!");
|
||||
}
|
||||
|
||||
if(obj->is64) {
|
||||
ElfSymBytes64 *b;
|
||||
|
|
@ -760,7 +769,8 @@ readsym(ElfObj *obj, int i, ElfSym *sym)
|
|||
}
|
||||
// fall through
|
||||
case ElfSymBindLocal:
|
||||
s = lookup(sym->name, version);
|
||||
if(!(thechar == '5' && (strcmp(sym->name, "$a") == 0 || strcmp(sym->name, "$d") == 0))) // binutils for arm generate these mapping symbols, ignore these
|
||||
s = lookup(sym->name, version);
|
||||
break;
|
||||
default:
|
||||
werrstr("%s: invalid symbol binding %d", sym->name, sym->bind);
|
||||
|
|
@ -797,6 +807,15 @@ reltype(char *pn, int elftype, uchar *siz)
|
|||
switch(R(thechar, elftype)) {
|
||||
default:
|
||||
diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype);
|
||||
case R('5', R_ARM_ABS32):
|
||||
case R('5', R_ARM_GOT32):
|
||||
case R('5', R_ARM_PLT32):
|
||||
case R('5', R_ARM_GOTOFF):
|
||||
case R('5', R_ARM_GOTPC):
|
||||
case R('5', R_ARM_THM_PC22):
|
||||
case R('5', R_ARM_REL32):
|
||||
case R('5', R_ARM_CALL):
|
||||
case R('5', R_ARM_V4BX):
|
||||
case R('6', R_X86_64_PC32):
|
||||
case R('6', R_X86_64_PLT32):
|
||||
case R('6', R_X86_64_GOTPCREL):
|
||||
|
|
|
|||
Loading…
Reference in New Issue