<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>