LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 30415 - lld has different section attribute merging vs ld.bfd
Summary: lld has different section attribute merging vs ld.bfd
Status: RESOLVED FIXED
Alias: None
Product: lld
Classification: Unclassified
Component: ELF (show other bugs)
Version: unspecified
Hardware: PC FreeBSD
: P normal
Assignee: Unassigned LLVM Bugs
URL:
Keywords:
Depends on:
Blocks: 23214
  Show dependency tree
 
Reported: 2016-09-16 10:23 PDT by emaste
Modified: 2019-07-25 22:24 PDT (History)
4 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description emaste 2016-09-16 10:23:56 PDT
LLD is not necessarily wrong here and what ld.bfd is doing is arguably a bug, but I'm submitting this PR for tracking one of the few outstanding issues linking FreeBSD/amd64 with LLD while looking for a solution.

We recently migrated to using a linker script instead of the seemingly obsolete -N command line flag for FreeBSD's boot loader components: https://svnweb.freebsd.org/base?view=revision&revision=305353

The linker script is straightforward:

---
/* $FreeBSD$ */
/* Merge text, data and bss together almost no padding */
OUTPUT_FORMAT("elf32-i386-freebsd")
OUTPUT_ARCH(i386)
ENTRY(_start)
SECTIONS {
  . = 0x08048000 + SIZEOF_HEADERS;
  .text : { *(.text) } =0x90909090      /* Pad with nops, if needed */
  .data : { *(.data) } PROVIDE(_edata = .);
  .bss  : { *(.bss) }  PROVIDE(_end = .);
}
---

From this GNU ld produces an object with all sections packed into a single RWE segment:

% readelf -l boot2.out

Elf file type is EXEC (Executable file)
Entry point 0x2000
There are 2 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000080 0x00002000 0x00002000 0x01456 0x027f8 RWE 0x10
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4

 Section to Segment mapping:
  Segment Sections...
   00     .text .rodata .data .bss 
   01     

while LLD produces an object with separate segments for sections with different permissions.
Comment 1 Rafael Ávila de Espíndola 2016-09-16 11:13:28 PDT
Why is having multiple PT_LOADs a problem?
Comment 2 Rafael Ávila de Espíndola 2016-09-16 11:37:47 PDT
If you want to merge it all in one output section, I think you can do

.all : { *(.text) *(.data) *(.bss) }
Comment 3 emaste 2016-09-16 12:14:56 PDT
> Why is having multiple PT_LOADs a problem?

Sorry, multiple PT_LOADs is not a problem per se, but the resulting binary produced by lld is too large.
Comment 4 emaste 2016-09-16 12:33:57 PDT
> .all : { *(.text) *(.data) *(.bss) }

With that I end up failing because there's no section for relocations:

mbr.o: In function `start':
(.text+0xd): relocation truncated to fit: R_386_16 against `.text'
Comment 5 Rafael Ávila de Espíndola 2016-10-31 16:41:00 PDT
(In reply to comment #4)
> > .all : { *(.text) *(.data) *(.bss) }
> 
> With that I end up failing because there's no section for relocations:
> 
> mbr.o: In function `start':
> (.text+0xd): relocation truncated to fit: R_386_16 against `.text'

Can you check if this is still a problem and upload a cpio if it is?
Comment 6 emaste 2016-11-22 06:56:11 PST
A little more information:

FreeBSD switched to a linker script for these boot loaders in r305353 (https://svnweb.freebsd.org/base?view=revision&revision=305353, https://reviews.freebsd.org/D7409)

However, it broke one of the loaders when using ld.bfd (https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=213491)
and was reverted in r307954 (https://svnweb.freebsd.org/base?view=revision&revision=307954)

Most of the boot components worked with the linker script version though, and I expect we'll fix the breakage and restore the use of the linker script.

I will try re-applying r305353 and generating a reproduction cpio at some point, but I believe the EFI loaders are more important to fix first and am helping George investigate those first.
Comment 7 Rafael Ávila de Espíndola 2016-11-27 20:05:37 PST
(In reply to comment #6)
> A little more information:
> 
> FreeBSD switched to a linker script for these boot loaders in r305353
> (https://svnweb.freebsd.org/base?view=revision&revision=305353,
> https://reviews.freebsd.org/D7409)
> 
> However, it broke one of the loaders when using ld.bfd
> (https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=213491)
> and was reverted in r307954
> (https://svnweb.freebsd.org/base?view=revision&revision=307954)
> 
> Most of the boot components worked with the linker script version though,
> and I expect we'll fix the breakage and restore the use of the linker script.
> 
> I will try re-applying r305353 and generating a reproduction cpio at some
> point, but I believe the EFI loaders are more important to fix first and am
> helping George investigate those first.

Note that given that we already support putting ro and rx together because of linker scripts, supporting the original feature might not be a big problem.
Comment 8 Fangrui Song 2019-07-25 22:24:07 PDT
lld doesn't create one single RWX PT_LOAD now. Closing because the issue has been fixed for a while.

# I test on a Linux machine, but the FreeBSD case is similar.
% clang -fuse-ld=lld -m32 a.c a.x -o a  # 5008 bytes

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x08048034 0x08048034 0x00140 0x00140 R   0x4
  INTERP         0x000174 0x08048174 0x08048174 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x08048000 0x08048000 0x00730 0x00730 R E 0x1000
  LOAD           0x000730 0x08048730 0x08048730 0x000d8 0x000d8 RW  0x1000
  LOAD           0x000808 0x08048808 0x08048808 0x00020 0x00021 RW  0x1000
  DYNAMIC        0x000738 0x08048738 0x08048738 0x000c8 0x000c8 RW  0x4
  GNU_RELRO      0x000730 0x08048730 0x08048730 0x000d8 0x01000 R   0x1
  GNU_EH_FRAME   0x000378 0x08048378 0x08048378 0x00044 0x00044 R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0
  NOTE           0x000188 0x08048188 0x08048188 0x00020 0x00020 R   0x4

After D64903 and D64906 are merged, the non-linker script case will look similar to this layout.

% clang -fuse-ld=bfd -m32 a.c a.x -o a.bfd  # 7148 bytes
% readelf -l a.bfd
...
Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x08048034 0x08048034 0x00120 0x00120 R   0x4
  INTERP         0x000154 0x08048154 0x08048154 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x08048000 0x08048000 0x005dc 0x005dc R E 0x1000
  LOAD           0x000f04 0x08049f04 0x08049f04 0x00118 0x0011c RW  0x1000
  DYNAMIC        0x000f0c 0x08049f0c 0x08049f0c 0x000f0 0x000f0 RW  0x4
  NOTE           0x000168 0x08048168 0x08048168 0x00020 0x00020 R   0x4
  GNU_EH_FRAME   0x0004c8 0x080484c8 0x080484c8 0x00034 0x00034 R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
  GNU_RELRO      0x000f04 0x08049f04 0x08049f04 0x000fc 0x000fc R   0x1

> Note that given that we already support putting ro and rx together because of linker scripts, supporting the original feature might not be a big problem.

After https://reviews.llvm.org/rLLD281978, we place R and RX sections in the RX PT_LOAD (`singleRoRx = true;` in ScriptParser.cpp). I actually want to flip this, to improve consistency with the non-linker script case, and to fix issues like https://bugs.llvm.org/show_bug.cgi?id=38784

People who want separate R PT_LOAD and RX PT_LOAD in linker script cases can enable --no-rosegment.