summaryrefslogtreecommitdiff
path: root/src/cmd/ld
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/ld')
-rw-r--r--src/cmd/ld/data.c31
-rw-r--r--src/cmd/ld/dwarf.c51
-rw-r--r--src/cmd/ld/elf.c38
-rw-r--r--src/cmd/ld/elf.h4
-rw-r--r--src/cmd/ld/go.c13
-rw-r--r--src/cmd/ld/ldmacho.c32
-rw-r--r--src/cmd/ld/lib.c70
-rw-r--r--src/cmd/ld/lib.h38
-rw-r--r--src/cmd/ld/pe.c8
-rw-r--r--src/cmd/ld/symtab.c30
10 files changed, 209 insertions, 106 deletions
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index a20b057ce..d27416dac 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -722,7 +722,7 @@ addsize(Sym *s, Sym *t)
void
dodata(void)
{
- int32 h, t, datsize;
+ int32 t, datsize;
Section *sect;
Sym *s, *last, **l;
@@ -732,23 +732,22 @@ dodata(void)
last = nil;
datap = nil;
- for(h=0; h<NHASH; h++) {
- for(s=hash[h]; s!=S; s=s->hash){
- if(!s->reachable || s->special)
- continue;
- if(STEXT < s->type && s->type < SXREF) {
- if(last == nil)
- datap = s;
- else
- last->next = s;
- s->next = nil;
- last = s;
- }
+
+ for(s=allsym; s!=S; s=s->allsym) {
+ if(!s->reachable || s->special)
+ continue;
+ if(STEXT < s->type && s->type < SXREF) {
+ if(last == nil)
+ datap = s;
+ else
+ last->next = s;
+ s->next = nil;
+ last = s;
}
}
for(s = datap; s != nil; s = s->next) {
- if(s->np > 0 && s->type == SBSS) // TODO: necessary?
+ if(s->np > 0 && s->type == SBSS)
s->type = SDATA;
if(s->np > s->size)
diag("%s: initialize bounds (%lld < %d)",
@@ -786,8 +785,7 @@ dodata(void)
s = datap;
for(; s != nil && s->type < SDATA; s = s->next) {
s->type = SRODATA;
- t = rnd(s->size, 4);
- s->size = t;
+ t = rnd(s->size, PtrSize);
s->value = datsize;
datsize += t;
}
@@ -834,7 +832,6 @@ dodata(void)
datsize = rnd(datsize, 4);
else
datsize = rnd(datsize, 8);
- s->size = t;
s->value = datsize;
datsize += t;
}
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
index 5ba4b7c64..fa55fcbb4 100644
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -6,7 +6,6 @@
// - eliminate DW_CLS_ if not used
// - package info in compilation units
// - assign global variables and types to their packages
-// - (upstream) type info for C parts of runtime
// - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg
// ptype struct '[]uint8' and qualifiers need to be quoted away
// - lexical scoping is lost, so gdb gets confused as to which 'main.i' you mean.
@@ -943,14 +942,16 @@ enum {
static char*
decodetype_structfieldname(Sym *s, int i)
{
+ Reloc *r;
+
// go.string."foo" 0x28 / 0x40
s = decode_reloc_sym(s, CommonSize + PtrSize + 2*4 + i*StructFieldSize);
if (s == nil) // embedded structs have a nil name.
return nil;
- s = decode_reloc_sym(s, 0); // string."foo"
- if (s == nil) // shouldn't happen.
+ r = decode_reloc(s, 0); // s has a pointer to the string data at offset 0
+ if (r == nil) // shouldn't happen.
return nil;
- return (char*)s->p; // the c-string
+ return (char*) r->sym->p + r->add; // the c-string
}
static Sym*
@@ -989,8 +990,8 @@ lookup_or_diag(char *n)
{
Sym *s;
- s = lookup(n, 0);
- if (s->size == 0) {
+ s = rlookup(n, 0);
+ if (s == nil || s->size == 0) {
diag("dwarf: missing type: %s", n);
errorexit();
}
@@ -1021,22 +1022,8 @@ defgotype(Sym *gotype)
if (die != nil)
return die;
- if (0 && debug['v'] > 2) {
- print("new type: %s @0x%08x [%d]", gotype->name, gotype->value, gotype->size);
- for (i = 0; i < gotype->size; i++) {
- if (!(i%8)) print("\n\t%04x ", i);
- print("%02x ", gotype->p[i]);
- }
- print("\n");
- for (i = 0; i < gotype->nr; i++) {
- print("\t0x%02x[%x] %d %s[%llx]\n",
- gotype->r[i].off,
- gotype->r[i].siz,
- gotype->r[i].type,
- gotype->r[i].sym->name,
- (vlong)gotype->r[i].add);
- }
- }
+ if (0 && debug['v'] > 2)
+ print("new type: %Y\n", gotype);
kind = decodetype_kind(gotype);
bytesize = decodetype_size(gotype);
@@ -1117,7 +1104,6 @@ defgotype(Sym *gotype)
fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5);
newrefattr(fld, DW_AT_type, defptrto(defgotype(s)));
}
- die = defptrto(die);
break;
case KindInterface:
@@ -1391,7 +1377,7 @@ static void
synthesizechantypes(DWDie *die)
{
DWDie *sudog, *waitq, *link, *hchan,
- *dws, *dww, *dwl, *dwh, *elemtype;
+ *dws, *dww, *dwh, *elemtype;
DWAttr *a;
int elemsize, linksize, sudogsize;
@@ -1430,21 +1416,10 @@ synthesizechantypes(DWDie *die)
newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT,
getattr(waitq, DW_AT_byte_size)->value, NULL);
- // link<T>
- dwl = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
- mkinternaltypename("link", getattr(elemtype, DW_AT_name)->data, NULL));
- copychildren(dwl, link);
- substitutetype(dwl, "link", defptrto(dwl));
- substitutetype(dwl, "elem", elemtype);
- newattr(dwl, DW_AT_byte_size, DW_CLS_CONSTANT,
- linksize + (elemsize > 8 ? elemsize - 8 : 0), NULL);
-
// hchan<T>
dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, NULL));
copychildren(dwh, hchan);
- substitutetype(dwh, "senddataq", defptrto(dwl));
- substitutetype(dwh, "recvdataq", defptrto(dwl));
substitutetype(dwh, "recvq", dww);
substitutetype(dwh, "sendq", dww);
substitutetype(dwh, "free", dws);
@@ -1463,12 +1438,8 @@ defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype)
if (strncmp(s, "go.string.", 10) == 0)
return;
- if (strncmp(s, "string.", 7) == 0)
- return;
- if (strncmp(s, "type._.", 7) == 0)
- return;
- if (strncmp(s, "type.", 5) == 0) {
+ if (strncmp(s, "type.", 5) == 0 && strcmp(s, "type.*") != 0) {
defgotype(sym);
return;
}
diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c
index d5b0b0311..b0cce4985 100644
--- a/src/cmd/ld/elf.c
+++ b/src/cmd/ld/elf.c
@@ -336,7 +336,7 @@ void
elfdynhash(void)
{
Sym *s, *sy;
- int i, h, nbucket, b;
+ int i, nbucket, b;
uchar *pc;
uint32 hc, g;
uint32 *chain, *buckets;
@@ -367,26 +367,24 @@ elfdynhash(void)
}
memset(chain, 0, nsym * sizeof(uint32));
memset(buckets, 0, nbucket * sizeof(uint32));
- for(h = 0; h<NHASH; h++) {
- for(sy=hash[h]; sy!=S; sy=sy->hash) {
- if (sy->dynid <= 0)
- continue;
-
- hc = 0;
- name = sy->dynimpname;
- if(name == nil)
- name = sy->name;
- for(pc = (uchar*)name; *pc; pc++) {
- hc = (hc<<4) + *pc;
- g = hc & 0xf0000000;
- hc ^= g >> 24;
- hc &= ~g;
- }
-
- b = hc % nbucket;
- chain[sy->dynid] = buckets[b];
- buckets[b] = sy->dynid;
+ for(sy=allsym; sy!=S; sy=sy->allsym) {
+ if (sy->dynid <= 0)
+ continue;
+
+ hc = 0;
+ name = sy->dynimpname;
+ if(name == nil)
+ name = sy->name;
+ for(pc = (uchar*)name; *pc; pc++) {
+ hc = (hc<<4) + *pc;
+ g = hc & 0xf0000000;
+ hc ^= g >> 24;
+ hc &= ~g;
}
+
+ b = hc % nbucket;
+ chain[sy->dynid] = buckets[b];
+ buckets[b] = sy->dynid;
}
adduint32(s, nbucket);
diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h
index df15cb115..b27ae679b 100644
--- a/src/cmd/ld/elf.h
+++ b/src/cmd/ld/elf.h
@@ -946,10 +946,10 @@ typedef Elf64_Shdr ElfShdr;
typedef Elf64_Phdr ElfPhdr;
void elfinit(void);
-ElfEhdr *getElfEhdr();
+ElfEhdr *getElfEhdr(void);
ElfShdr *newElfShstrtab(vlong);
ElfShdr *newElfShdr(vlong);
-ElfPhdr *newElfPhdr();
+ElfPhdr *newElfPhdr(void);
uint32 elfwritehdr(void);
uint32 elfwritephdrs(void);
uint32 elfwriteshdrs(void);
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c
index 3c1e230b4..055163d08 100644
--- a/src/cmd/ld/go.c
+++ b/src/cmd/ld/go.c
@@ -135,6 +135,7 @@ ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence)
if(debug['u'] && whence != ArchiveObj &&
(p0+6 > p1 || memcmp(p0, " safe\n", 6) != 0)) {
fprint(2, "%s: load of unsafe package %s\n", argv0, filename);
+ nerrors++;
errorexit();
}
if(p0 < p1) {
@@ -657,27 +658,25 @@ deadcode(void)
else
last->next = nil;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->hash)
+ for(s = allsym; s != S; s = s->allsym)
if(strncmp(s->name, "weak.", 5) == 0) {
s->special = 1; // do not lay out in data segment
s->reachable = 1;
+ s->hide = 1;
}
}
void
doweak(void)
{
- int i;
Sym *s, *t;
// resolve weak references only if
// target symbol will be in binary anyway.
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->hash) {
+ for(s = allsym; s != S; s = s->allsym) {
if(strncmp(s->name, "weak.", 5) == 0) {
- t = lookup(s->name+5, s->version);
- if(t->type != 0 && t->reachable) {
+ t = rlookup(s->name+5, s->version);
+ if(t && t->type != 0 && t->reachable) {
s->value = t->value;
s->type = t->type;
} else {
diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c
index 7e38db0e4..bbb21d51a 100644
--- a/src/cmd/ld/ldmacho.c
+++ b/src/cmd/ld/ldmacho.c
@@ -422,6 +422,7 @@ void
ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
{
int i, j, is64;
+ uint64 secaddr;
uchar hdr[7*4], *cmdp;
uchar tmp[4];
uchar *dat;
@@ -581,7 +582,11 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
else
s->type = SRODATA;
} else {
- s->type = SDATA;
+ if (strcmp(sect->name, "__bss") == 0) {
+ s->type = SBSS;
+ s->np = 0;
+ } else
+ s->type = SDATA;
}
if(s->type == STEXT) {
if(etextp)
@@ -751,8 +756,29 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
rp->siz = rel->length;
rp->type = 512 + (rel->type<<1) + rel->pcrel;
rp->off = rel->addr;
-
- rp->add = e->e32(s->p+rp->off);
+
+ // Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
+ if (thechar == '6' && rel->extrn == 0 && rel->type == 1) {
+ // Calculate the addend as the offset into the section.
+ //
+ // The rip-relative offset stored in the object file is encoded
+ // as follows:
+ //
+ // movsd 0x00000360(%rip),%xmm0
+ //
+ // To get the absolute address of the value this rip-relative address is pointing
+ // to, we must add the address of the next instruction to it. This is done by
+ // taking the address of the relocation and adding 4 to it (since the rip-relative
+ // offset can at most be 32 bits long). To calculate the offset into the section the
+ // relocation is referencing, we subtract the vaddr of the start of the referenced
+ // section found in the original object file.
+ //
+ // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
+ secaddr = c->seg.sect[rel->symnum-1].addr;
+ rp->add = e->e32(s->p+rp->off) + rp->off + 4 - secaddr;
+ } else
+ rp->add = e->e32(s->p+rp->off);
+
// For i386 Mach-O PC-relative, the addend is written such that
// it *is* the PC being subtracted. Use that to make
// it match our version of PC-relative.
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index e645502b3..8cd570463 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -61,6 +61,7 @@ void
libinit(void)
{
fmtinstall('i', iconv);
+ fmtinstall('Y', Yconv);
mywhatsys(); // get goroot, goarch, goos
if(strcmp(goarch, thestring) != 0)
print("goarch is not known: %s\n", goarch);
@@ -470,8 +471,8 @@ eof:
diag("truncated object file: %s", pn);
}
-Sym*
-lookup(char *symb, int v)
+static Sym*
+_lookup(char *symb, int v, int creat)
{
Sym *s;
char *p;
@@ -485,10 +486,12 @@ lookup(char *symb, int v)
// not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it.
h &= 0xffffff;
h %= NHASH;
+ c = symb[0];
for(s = hash[h]; s != S; s = s->hash)
- if(s->version == v)
if(memcmp(s->name, symb, l) == 0)
return s;
+ if(!creat)
+ return nil;
s = mal(sizeof(*s));
if(debug['v'] > 1)
@@ -508,9 +511,25 @@ lookup(char *symb, int v)
s->size = 0;
hash[h] = s;
nsymbol++;
+
+ s->allsym = allsym;
+ allsym = s;
return s;
}
+Sym*
+lookup(char *name, int v)
+{
+ return _lookup(name, v, 1);
+}
+
+// read-only lookup
+Sym*
+rlookup(char *name, int v)
+{
+ return _lookup(name, v, 0);
+}
+
void
copyhistfrog(char *buf, int nbuf)
{
@@ -829,7 +848,7 @@ unmal(void *v, uint32 n)
// Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync.
/*
* Convert raw string to the prefix that will be used in the symbol table.
- * Invalid bytes turn into %xx. Right now the only bytes that need
+ * Invalid bytes turn into %xx. Right now the only bytes that need
* escaping are %, ., and ", but we escape all control characters too.
*/
static char*
@@ -1104,7 +1123,7 @@ static Sym *newstack;
enum
{
HasLinkRegister = (thechar == '5'),
- CallSize = (!HasLinkRegister)*PtrSize, // bytes of stack required for a call
+ CallSize = (!HasLinkRegister)*PtrSize, // bytes of stack required for a call
};
void
@@ -1130,7 +1149,7 @@ dostkcheck(void)
// Check calling contexts.
// Some nosplits get called a little further down,
- // like newproc and deferproc. We could hard-code
+ // like newproc and deferproc. We could hard-code
// that knowledge but it's more robust to look at
// the actual call sites.
for(s = textp; s != nil; s = s->next) {
@@ -1283,11 +1302,44 @@ headtype(char *name)
void
undef(void)
{
- int i;
Sym *s;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->hash)
+ for(s = allsym; s != S; s = s->allsym)
if(s->type == SXREF)
diag("%s(%d): not defined", s->name, s->version);
}
+
+int
+Yconv(Fmt *fp)
+{
+ Sym *s;
+ Fmt fmt;
+ int i;
+ char *str;
+
+ s = va_arg(fp->args, Sym*);
+ if (s == S) {
+ fmtprint(fp, "<nil>");
+ } else {
+ fmtstrinit(&fmt);
+ fmtprint(&fmt, "%s @0x%08x [%d]", s->name, s->value, s->size);
+ for (i = 0; i < s->size; i++) {
+ if (!(i%8)) fmtprint(&fmt, "\n\t0x%04x ", i);
+ fmtprint(&fmt, "%02x ", s->p[i]);
+ }
+ fmtprint(&fmt, "\n");
+ for (i = 0; i < s->nr; i++) {
+ fmtprint(&fmt, "\t0x%04x[%x] %d %s[%llx]\n",
+ s->r[i].off,
+ s->r[i].siz,
+ s->r[i].type,
+ s->r[i].sym->name,
+ (vlong)s->r[i].add);
+ }
+ str = fmtstrflush(&fmt);
+ fmtstrcpy(fp, str);
+ free(str);
+ }
+
+ return 0;
+}
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index adde2c9ff..646aeb535 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -28,8 +28,37 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-// Where symbol table data gets mapped into memory.
-#define SYMDATVA 0x99LL<<24
+enum
+{
+ Sxxx,
+
+ /* order here is order in output file */
+ STEXT,
+ SELFDATA,
+ SMACHOPLT,
+ STYPE,
+ SSTRING,
+ SGOSTRING,
+ SRODATA,
+ SDATA,
+ SMACHO, /* Mach-O __nl_symbol_ptr */
+ SMACHOGOT,
+ SWINDOWS,
+ SBSS,
+
+ SXREF,
+ SMACHODYNSTR,
+ SMACHODYNSYM,
+ SMACHOINDIRECTPLT,
+ SMACHOINDIRECTGOT,
+ SFILE,
+ SCONST,
+ SDYNIMPORT,
+
+ SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */
+
+ NHASH = 100003,
+};
typedef struct Library Library;
struct Library
@@ -79,6 +108,7 @@ EXTERN Library* library;
EXTERN int libraryp;
EXTERN int nlibrary;
EXTERN Sym* hash[NHASH];
+EXTERN Sym* allsym;
EXTERN Sym* histfrog[MAXHIST];
EXTERN uchar fnuxi8[8];
EXTERN uchar fnuxi4[4];
@@ -106,6 +136,7 @@ void asmlc(void);
void histtoauto(void);
void collapsefrog(Sym *s);
Sym* lookup(char *symb, int v);
+Sym* rlookup(char *symb, int v);
void nuxiinit(void);
int find1(int32 l, int c);
int find2(int32 l, int c);
@@ -243,3 +274,6 @@ EXTERN char* headstring;
extern Header headers[];
int headtype(char*);
+
+int Yconv(Fmt*);
+#pragma varargck type "Y" Sym*
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
index e72b0b2a0..0d4240e36 100644
--- a/src/cmd/ld/pe.c
+++ b/src/cmd/ld/pe.c
@@ -171,12 +171,10 @@ initdynimport(void)
Imp *m;
Dll *d;
Sym *s, *dynamic;
- int i;
dr = nil;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->hash) {
+ for(s = allsym; s != S; s = s->allsym) {
if(!s->reachable || !s->dynimpname || s->dynexport)
continue;
for(d = dr; d != nil; d = d->next) {
@@ -312,12 +310,10 @@ scmp(const void *p1, const void *p2)
static void
initdynexport(void)
{
- int i;
Sym *s;
nexport = 0;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->hash) {
+ for(s = allsym; s != S; s = s->allsym) {
if(!s->reachable || !s->dynimpname || !s->dynexport)
continue;
if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) {
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index 22777b6b5..aefe0b1af 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -340,6 +340,8 @@ putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
void
symtab(void)
{
+ Sym *s;
+
// Define these so that they'll get put into the symbol table.
// data.c:/^address will provide the actual values.
xdefine("text", STEXT, 0);
@@ -351,11 +353,39 @@ symtab(void)
xdefine("end", SBSS, 0);
xdefine("epclntab", SRODATA, 0);
xdefine("esymtab", SRODATA, 0);
+
+ // pseudo-symbols to mark locations of type, string, and go string data.
+ s = lookup("type.*", 0);
+ s->type = STYPE;
+ s->size = 0;
+ s->reachable = 1;
+
+ s = lookup("go.string.*", 0);
+ s->type = SGOSTRING;
+ s->size = 0;
+ s->reachable = 1;
symt = lookup("symtab", 0);
symt->type = SRODATA;
symt->size = 0;
symt->reachable = 1;
+
+ // assign specific types so that they sort together.
+ // within a type they sort by size, so the .* symbols
+ // just defined above will be first.
+ // hide the specific symbols.
+ for(s = allsym; s != S; s = s->allsym) {
+ if(!s->reachable || s->special || s->type != SRODATA)
+ continue;
+ if(strncmp(s->name, "type.", 5) == 0) {
+ s->type = STYPE;
+ s->hide = 1;
+ }
+ if(strncmp(s->name, "go.string.", 10) == 0) {
+ s->type = SGOSTRING;
+ s->hide = 1;
+ }
+ }
genasmsym(putsymb);
}