<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Tue, Nov 7, 2017 at 6:59 PM, Rafael Avila de Espindola <span dir="ltr"><<a href="mailto:rafael.espindola@gmail.com" target="_blank">rafael.espindola@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">Rui Ueyama via llvm-dev <<a href="mailto:llvm-dev@lists.llvm.org">llvm-dev@lists.llvm.org</a>> writes:<br>
<br>
> tl;dr: TLSDESC have solved most problems in formerly inefficient TLS access<br>
> models, so I think we can drop TLS relaxation support from lld.<br>
><br>
> lld's code to handle relocations is a mess; the code consists of a lot of<br>
> cascading "if"s and needs a lot of prior knowledge to understand what it is<br>
> doing. Honestly it is head-scratching and needs serious refactoring. I'm<br>
> trying to simplify it to make it manageable again, and I'm now focusing on<br>
> the TLS relaxations.<br>
><br>
> Thread-local variables in ELF is complicated. The ELF TLS specification [1]<br>
> defines 4 different access models: General Dynamic, Local Dynamic, Initial<br>
> Exec and Local Exec.<br>
><br>
> I'm not going into the details of the spec here, but the reason why we have<br>
> so many different models for the same feature is because they were<br>
> different in speed, and we have to use (formerly) slow models when we know<br>
> less about their run-time memory layout at compile-time or link-time. So,<br>
> there was a trade-off between generality and performance. For example, if<br>
> you want to use thread-local variables in a dlopen(2)'able DSO, you need to<br>
> choose the slowest model. If a linker knows at link-time that a more<br>
> restricted access model is applicable (e.g. if it is linking a main<br>
> executable, it knows for sure that it is not creating a DSO that will be<br>
> used via dlopen), the linker is allowed to rewrite instructions to load<br>
> thread-local variables to use a faster access model.<br>
><br>
> What makes the situation more complicated is the presence of a new method<br>
> of accessing thread-local variables. After the ELF TLS spec was defined,<br>
> TLSDESC [2] was proposed and implemented. With that method, General Dynamic<br>
> and Local Dynamic models (that were pretty slow in the original spec) are<br>
> as fast as much faster Initial Exec model. TLSDESC doesn't have a trade-off<br>
> of dlopen'ability and access speed. According to [2], it also reduces the<br>
> size of generated DSOs. So it seems like TLSDESC is strictly a better way<br>
> of accessing thread-local variables than the old way, and the thread-local<br>
> variable's performance problem (that the TLS ELF spec was trying to address<br>
> by defining four different access models and relaxations in between)<br>
> doesn't seem a real issue anymore.<br>
><br>
> lld supports all TLS relaxations as defined by the ELF TLS spec. I accepted<br>
> the patches to implement all these features without thinking hard enough<br>
> about it, but on second thought, that was likely a wrong decision. Being a<br>
> new linker, we don't need to trace the history of the evolution of the ELF<br>
> spec. Instead, we should have implemented whatever it makes sense now.<br>
><br>
> So, I'd like to propose we drop TLS relaxations from lld, including Initial<br>
> Exec → Local Exec. Dropping IE→LE is strictly speaking a degradation, but I<br>
> don't think that is important. We don't have optimizations for much more<br>
> frequent variable access patterns such as locally-accessed variables that<br>
> have GOT slots (which in theory we can skip GOT access because GOT slot<br>
> values are known at link-time), so it is odd that we are only serious about<br>
> TLS variables, which are usually much less important. Even if it would turn<br>
> out that we want it after implementing more important relaxations, I'd like<br>
> to drop it for now and reimplement it in a different way later.<br>
><br>
> This should greatly simplifies the code because it does not only reduce the<br>
> complexity and amount of the existing code, but also reduces the amount of<br>
> knowledge you need to have to read the code, without sacrificing<br>
> performance of lld-generated files in practice.<br>
><br>
> Thoughts?<br>
<br>
</div></div>I don't think we can do it.<br>
<br>
The main thing we have to keep in mind is that not everyone is using<br>
TLSDESC. In fact, clang doesn't even support -mtls-dialect=gnu2.<br></blockquote><div><br></div><div>Oh, okay, that is a surprise to me. There's no reason not to support that and make it default, I wasn't even try that. We definitely should support that.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
If everyone switches to TLSDESC, then I am OK with dropping<br>
optimizations for the old model.<br>
<br>
But even with TLSDESC we still need linker relaxations. The TLSDESC idea<br>
solves some of the GD -> IE cost in the case where the .so is not<br>
dlopened, but that is it. Note that AARCH64 that is TLSDESC only has<br>
relaxations.<br>
<br>
So I am strongly against removing either non TLSDESC support of support<br>
for the relaxations.<br></blockquote><div><br></div><div>It's still pretty arguable. By default, compilers use General Dynamic model with -fpic, and Initial Exec without -fpic. lld doesn't do any relaxation if -shared is given. So, if you are creating a DSO, thread-local variables in the DSO are accessed using Global Dynamic model. No relaxations are involved.</div><div><br></div><div>If you are creating an executable and if your executable is not position-independent, you're using Initial Exec model by default which is as fast as variables accessed through GOT. If you really want to use Local Exec model, you can pass -ftls-model=local-exec to compilers.</div><div><br></div><div>If you are creating a position-independent executable and you want to use Initial Exec or Local Exec, you can do that by passing -ftls-model={initial-exec,local-exec} to compilers.</div><div><br></div><div>So I don't see a strong reason to do a complicated instruction rewriting in the linker. I feel more like we should do whatever it is instructed to do by command line options and input object files. You are for example free to pass the -fPIC option to create object files and still let the linker to create a non-PIC executable, even though these combinations doesn't make much sense and produces slightly inefficient binary. If you don't like it, you can fix the compiler options. Thread-local variables can be considered in the same way, no?</div></div></div></div>