This is an archive of the discontinued LLVM Phabricator instance.

Set DF_TEXTREL only if text relocations are really needed.
AbandonedPublic

Authored by MaskRay on May 7 2018, 1:04 PM.

Details

Summary

bfd/gold emit DF_TEXTREL/DT_TEXTREL only when text relocations are really needed.

Event Timeline

MaskRay created this revision.May 7 2018, 1:04 PM
MaskRay updated this revision to Diff 145525.May 7 2018, 1:18 PM

Update test

ruiu added a comment.May 7 2018, 1:25 PM

This is perhaps harmless, but I'm leaning towards not doing this unless there's a reason to do this. I understand why GNU linkers want to do this -- it is because they allow text relocations by default. On the other hand, lld sets DF_TEXTREL only when you explicitly make lld allow text relocations. So, simply setting the flag when the flag is given makes sense to me. Can I ask your motivation of making this change?

MaskRay added a comment.EditedMay 7 2018, 1:29 PM

The motivation is that IFUNC (e.g. R_X86_64_IRELATIVE) is incompatible with DF_TEXTREL. Setting DF_TEXTREL unconditionally may be sometimes harmful.

bfd will error when both IFUNC and DF_TEXTREL are used in non-writable segments.

// bfd/elfxx-x86.c:1291
  if ((info->flags & DF_TEXTREL) != 0)
    {
      if (htab->readonly_dynrelocs_against_ifunc)
        {
          info->callbacks->einfo
            (_("%P%X: read-only segment has dynamic IFUNC relocations;"
              " recompile with -fPIC\n"));
          bfd_set_error (bfd_error_bad_value);
          return FALSE;
        }

      if (!add_dynamic_entry (DT_TEXTREL, 0))
        return FALSE;
    }

gold does not error. But glibc ld.so will crash when IFUNC relocations are resolved in runtime

// elf/get-dynamic-info.h  DF_TEXTREL implies DT_TEXTREL
if (l->l_flags & DF_TEXTREL)
    info[DT_TEXTREL] = info[DT_FLAGS];

// elf/dl-reloc.c
  if (__builtin_expect (l->l_info[DT_TEXTREL] != NULL, 0))
  {
    /////////// the program text segment is remapped as read+write
    ///// PROT_EXEC should also be set if ifunc is used
    if (__mprotect (newp->start, newp->len, PROT_READ|PROT_WRITE) < 0)
  
    ////// IFUNC (R_X86_64_IRELATIVE) is resolved in this call
    /// Code in the program segment is executed while the map is non-executable
    ELF_DYNAMIC_RELOCATE (l, lazy, consider_profiling, skip_ifunc);
ruiu added a comment.May 7 2018, 2:00 PM

I don't know if setting DF_TEXTREL flag only when text relocation is actually needed is a right solution to solve the issue you described. In lld, when you pass -z textrel, we should assume that the program really needs a text relocations, because otherwise you wouldn't pass that flag to the linker. If it is not compatible with IFUNC, we should emit a warning when we find a IFUNC symbol, no?

joerg added a subscriber: joerg.May 8 2018, 3:10 PM

"-z textrel" can also be used in build instructions if some platforms will need it, even if not all of them do.

I consider the ifunc in combination with relro example as primary case for those issues a design bug in at least GNU ld. It's not even about text relocations really.

grimar added a subscriber: grimar.May 10 2018, 1:43 AM
MaskRay abandoned this revision.Oct 9 2018, 5:22 PM

I feel lld's -z notext -z text is better than ld.bfd/gold's on-demand DT_TEXTREL tag. FWIW, glibc 2.19 (the next release) has addressed the incompatibility between DT_TEXTREL and IFUNC https://sourceware.org/bugzilla/show_bug.cgi?id=20480#c19