Repository: go
Issue: cmd/link: c-archive Output Mode Forces `Initial-Exec` TLS model
Labels: NeedsInvestigation,compiler/runtime

### What version of Go are you using (`go version`)?

<pre>
$ go version
go version go1.17.1 linux/amd64
</pre>

### Does this issue reproduce with the latest release?
Yes


### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.17.1"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build1642499936=/tmp/go-build -gno-record-gcc-switches"
</pre></details>

### What did you do?

Full Gist is available here - https://gist.github.com/auzhva/6e3660c2433f7ead765d4d09e645013b

In provided example there are 3 files:

- app.c - sample loader app
- lib.c - sample C-library
- lib.go - sample Go-library

If built in below fashion it works:
```shell
go build -o libGoShared.so -buildmode=c-shared ./lib.go
gcc -shared -lpthread -fPIC lib.c -o libClibShared.so -lGoShared -L.
gcc app.c -o app -ldl
```

Then when running `./app` it's fine.

While if I do below it fails with `cannot allocate memory in static TLS block` error.

```
go build -ldflags="-s -w" -o libGoStatic.a -buildmode=c-archive ./lib.go
gcc -shared -lpthread -fPIC lib.c -o libClibStatic.so -lGoStatic -L.
gcc app.c -o app -ldl
```

#### More investigation on STATIC_TLS flag

It appears that Go always builds with `Initial-Exec` TLS model, which appears to lead to `STATIC_TLS` flag being set to produced ELF binaries. 

This is easily visible with below:
```
$ readelf --dynamic -W libGoShared.so 
... skipped ...
 0x000000000000001e (FLAGS)              SYMBOLIC STATIC_TLS
... skipped ...
```

This is a case with `c-shared` library itself. But when `c-archive` is produced then whatever upper code will use it - it inherits STATIC_TLS flag.

So in second (faulty) example above the entire `libClibShared.so` inherits STATIC_TLS flag as well. At least on x86_64 arch (in theory this can be arch-dependent).

#### Ok, there is STATIC_TLS flag. So what?

Loading STATIC_TLS images is a complicated thing.

In linux version glibc it allocates pre-populated constant `surplus` of 512 bytes in TLS block for further unspecified use. It's defined here - https://sourceware.org/git/?p=glibc.git;a=blob;f=elf/dl-tls.c;h=d554ae44976bc494da4e41aaa4f6ecb5ca2ca4be;hb=HEAD

If I'm checking sizes of `.tbss/.tdata` sections via `readelf -S` then I see that go uses only 0x10 bytes of TLS. Which is lower then glibc surplus. And theoretically glibc is able to `dlopen()` up to 32 go libs until it will run out of the buffer.

But it doesn't work with `c-archive`. Go lib in `c-archive` mode requires same 16 bytes of TLS stack, but other code may have additional TLS requirements. So if additional code needs more TLS then c-archive plus that code runs out of glibc boundaries and entire thing fails.

That wouldn't have been happening if `c-shared` and `c-archive` would've not been forcing Initial-TLS TLS models. As this 512-byte glibc limit applies only to that model. And any of the other 3 models (General Dynamic, Local Dynamic, Local Executable) do not have this limit.

### What did you expect to see?

Both c-shared and c-archive cases working.

### What did you see instead?

C-archive case failing.