diff options
| author | Ian Lance Taylor <iant@golang.org> | 2013-03-27 13:27:35 -0700 |
|---|---|---|
| committer | Ian Lance Taylor <iant@golang.org> | 2013-03-27 13:27:35 -0700 |
| commit | 30e29ee9b6b71a4c40f781c513a8680e8f2c4f64 (patch) | |
| tree | 4a9fcc5e648792965796691618f7c69524820f5b /src/cmd/ld/data.c | |
| parent | 23482db9f1d6cc4ad7a74c9f6f807954c39ab701 (diff) | |
| download | go-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.c | 31 |
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; |
