aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/ld/data.c
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2013-03-27 13:27:35 -0700
committerIan Lance Taylor <iant@golang.org>2013-03-27 13:27:35 -0700
commit30e29ee9b6b71a4c40f781c513a8680e8f2c4f64 (patch)
tree4a9fcc5e648792965796691618f7c69524820f5b /src/cmd/ld/data.c
parent23482db9f1d6cc4ad7a74c9f6f807954c39ab701 (diff)
downloadgo-30e29ee9b6b71a4c40f781c513a8680e8f2c4f64.tar.xz
cmd/ld: emit TLS relocations during external linking
This CL was written by rsc. I just tweaked 8l. This CL adds TLS relocation to the ELF .o file we write during external linking, so that the host linker (gcc) can decide the final location of m and g. Similar relocations are not necessary on OS X because we use an alternate program start-time mechanism to acquire thread-local storage. Similar relocations are not necessary on ARM or Plan 9 or Windows because external linking mode is not yet supported on those systems. On almost all ELF systems, the references we use are like %fs:-0x4 or %gs:-0x4, which we write in 6a/8a as -0x4(FS) or -0x4(GS). On Linux/ELF, however, Xen's lack of support for this mode forced us long ago to use a two-instruction sequence: first we load %gs:0x0 into a register r, and then we use -0x4(r). (The ELF program loader arranges that %gs:0x0 contains a regular pointer to that same memory location.) In order to relocate those -0x4(r) references, the linker must know where they are. This CL adds the equivalent notation -0x4(r)(GS*1) for this purpose: it assembles to the same encoding as -0x4(r) but the (GS*1) indicates to the linker that this is one of those thread-local references that needs relocation. Thanks to Elias Naur for reminding me about this missing piece and also for writing the test. R=r CC=golang-dev https://golang.org/cl/7891047
Diffstat (limited to 'src/cmd/ld/data.c')
-rw-r--r--src/cmd/ld/data.c31
1 files changed, 25 insertions, 6 deletions
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index b70d4636cc..9f7ae0c409 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -172,7 +172,7 @@ relocsym(Sym *s)
if(r->sym != S && r->sym->type == SDYNIMPORT)
diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, r->type);
- if(r->sym != S && !r->sym->reachable)
+ if(r->sym != S && r->sym->type != STLSBSS && !r->sym->reachable)
diag("unreachable sym in relocation: %s %s", s->name, r->sym->name);
switch(r->type) {
@@ -181,6 +181,10 @@ relocsym(Sym *s)
if(linkmode == LinkExternal || archreloc(r, s, &o) < 0)
diag("unknown reloc %d", r->type);
break;
+ case D_TLS:
+ r->done = 0;
+ o = 0;
+ break;
case D_ADDR:
if(linkmode == LinkExternal && r->sym->type != SCONST) {
r->done = 0;
@@ -1193,11 +1197,7 @@ dodata(void)
sect->vaddr = datsize;
lookup("noptrbss", 0)->sect = sect;
lookup("enoptrbss", 0)->sect = sect;
- for(; s != nil; s = s->next) {
- if(s->type > SNOPTRBSS) {
- cursym = s;
- diag("unexpected symbol type %d", s->type);
- }
+ for(; s != nil && s->type == SNOPTRBSS; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
s->value = datsize;
@@ -1205,6 +1205,25 @@ dodata(void)
}
sect->len = datsize - sect->vaddr;
lookup("end", 0)->sect = sect;
+
+ if(iself && linkmode == LinkExternal && s != nil && s->type == STLSBSS) {
+ sect = addsection(&segdata, ".tbss", 06);
+ sect->align = PtrSize;
+ sect->vaddr = 0;
+ datsize = 0;
+ for(; s != nil && s->type == STLSBSS; s = s->next) {
+ datsize = aligndatsize(datsize, s);
+ s->sect = sect;
+ s->value = datsize;
+ datsize += s->size;
+ }
+ sect->len = datsize;
+ }
+
+ if(s != nil) {
+ cursym = nil;
+ diag("unexpected symbol type %d for %s", s->type, s->name);
+ }
/* we finished segdata, begin segtext */
s = datap;