<html>
<head>
<base href="https://bugs.llvm.org/">
</head>
<body><table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Bug ID</th>
<td><a class="bz_bug_link
bz_status_NEW "
title="NEW - R_386_TLS_LDO_32 does not respect existing offset"
href="https://bugs.llvm.org/show_bug.cgi?id=32634">32634</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>R_386_TLS_LDO_32 does not respect existing offset
</td>
</tr>
<tr>
<th>Product</th>
<td>lld
</td>
</tr>
<tr>
<th>Version</th>
<td>unspecified
</td>
</tr>
<tr>
<th>Hardware</th>
<td>PC
</td>
</tr>
<tr>
<th>OS</th>
<td>All
</td>
</tr>
<tr>
<th>Status</th>
<td>NEW
</td>
</tr>
<tr>
<th>Severity</th>
<td>enhancement
</td>
</tr>
<tr>
<th>Priority</th>
<td>P
</td>
</tr>
<tr>
<th>Component</th>
<td>ELF
</td>
</tr>
<tr>
<th>Assignee</th>
<td>unassignedbugs@nondot.org
</td>
</tr>
<tr>
<th>Reporter</th>
<td>smeenai@fb.com
</td>
</tr>
<tr>
<th>CC</th>
<td>llvm-bugs@lists.llvm.org
</td>
</tr></table>
<p>
<div>
<pre>% cat tls.cpp
struct s {
int i;
int j;
};
static __thread s t;
inline int geti() { return t.i; }
int callgeti() { return geti(); }
inline int getj() { return t.j; }
int callgetj() { return getj(); }
% clang++ -target i686-linux-gnu -fuse-ld=lld -shared -fPIC \
-nostdlib -o libtls.so tls.cpp
% objdump -d libtls.so | grep -A 1 'call.*__tls_get_addr'
1059: e8 72 00 00 00 call 10d0 <___tls_get_addr@plt>
105e: 8b 80 00 00 00 00 mov 0x0(%eax),%eax
--
1089: e8 42 00 00 00 call 10d0 <___tls_get_addr@plt>
108e: 8b 80 00 00 00 00 mov 0x0(%eax),%eax
In other words, both t.i and t.j got resolved to the same memory location. (The
first __tls_get_addr call is from geti; the second from getj.) I apologize for
the inline functions song and dance in the C++ source; I wasn't able to get
clang to produce R_386_TLS_LDO_32 relocations without it.
Looking into the cause:
% clang++ -target i686-linux-gnu -fPIC -c tls.cpp
% objdump -dr tls.o | grep -B 1 R_386_TLS_LDO_32
1e: 8b 80 00 00 00 00 mov 0x0(%eax),%eax
20: R_386_TLS_LDO_32 t
--
1e: 8b 80 04 00 00 00 mov 0x4(%eax),%eax
20: R_386_TLS_LDO_32 t
Again, the first one is from geti, and the second from getj. It looks like the
bytes corresponding to the R_386_TLS_LDO_32 already contain the struct offset,
but lld isn't respecting that struct offset when processing the relocation.
This is only an issue on x86. Comparing to x86_64:
% clang++ -target x86_64-linux-gnu -fPIC -c tls.cpp
% objdump -dr tls.o | grep -B 1 R_X86_64_DTPOFF32
10: 8b 80 00 00 00 00 mov 0x0(%rax),%eax
12: R_X86_64_DTPOFF32 t
--
10: 8b 80 00 00 00 00 mov 0x0(%rax),%eax
12: R_X86_64_DTPOFF32 t+0x4
On x86_64, the bytes corresponding to the R_X86_64_DTPOFF32 are always 0, and
the struct offset seems to be part of the relocation itself, so lld is able to
handle it correctly.</pre>
</div>
</p>
<hr>
<span>You are receiving this mail because:</span>
<ul>
<li>You are on the CC list for the bug.</li>
</ul>
</body>
</html>