Note: This is a beta release of Red Hat Bugzilla 5.0. The data contained within is a snapshot of the live data so any changes you make will not be reflected in the production Bugzilla. Also email is disabled so feel free to test any aspect of the site that you want. File any problems you find or give feedback here.
Bug 78871 - bfd/elf allows only 2 PT_LOAD segments/phdrs
Summary: bfd/elf allows only 2 PT_LOAD segments/phdrs
Alias: None
Product: Red Hat Linux
Classification: Retired
Component: binutils
Version: 8.0
Hardware: i686
OS: Linux
Target Milestone: ---
Assignee: Jakub Jelinek
QA Contact:
Depends On:
TreeView+ depends on / blocked
Reported: 2002-12-02 16:35 UTC by Need Real Name
Modified: 2005-10-31 22:00 UTC (History)
1 user (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Last Closed: 2004-10-02 20:50:31 UTC

Attachments (Terms of Use)
Source file to show bug (deleted)
2002-12-02 16:37 UTC, Need Real Name
no flags Details
Linker script that shows bug (deleted)
2002-12-02 16:39 UTC, Need Real Name
no flags Details
New patch (deleted)
2002-12-07 02:17 UTC, Need Real Name
no flags Details | Diff

Description Need Real Name 2002-12-02 16:35:34 UTC
From Bugzilla Helper:
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)

Description of problem:
IMHO, the following is too restrictive in bfd/elf.c:

static bfd_size_type
get_program_header_size (abfd)
     bfd *abfd;
  /* Assume we will need exactly two PT_LOAD segments: one for text
     and one for data.  */
  segs = 2;

There are times when one would like to allocate a new data/bss segment
to be loaded at a specific virtual address, but since the first pass of
ld has assumed that the program headers will only have 2 PT_LOAD
segments, though the second pass does allocate a new PT_LOAD segment on
encountering the section at the specific virtual address, the following
check fails:

static boolean
assign_file_positions_for_segments (abfd)
     bfd *abfd;
 /* If we already counted the number of program segments, make sure
     that we allocated enough space.  This happens when SIZEOF_HEADERS
     is used in a linker script.  */
  alloc = elf_tdata (abfd)->program_header_size / bed->s->sizeof_phdr;
  if (alloc != 0 && count > alloc)
       (_("%s: Not enough room for program headers (allocated %u, need
        bfd_get_filename (abfd), alloc, count));
      bfd_set_error (bfd_error_bad_value);
      return false;

Version-Release number of selected component (if applicable):

How reproducible:

Steps to Reproduce:
1. gcc -c test.c
2. ld --dynamic-linker ... ld_map test.o -o test

Actual Results:  /usr/bin/ld: test: Not enough room for program headers 
(allocated 6, need 7)
/usr/bin/ld: final link failed: Bad value

Expected Results:  No error messages

Additional info:

So, I am proposing that if there is no good way around this bug, then we
arbitrarily chose a large number of PT_LOAD program headers in the first
pass, and then let the second pass truncate the number of program
headers if there are only 2 PT_LOAD segments, for example.

I tried allowing 3 PT_LOAD segments, and it works for both the normal 2
PT_LOAD segments case and the 3 PT_LOAD segments case.

The final ELF executable produced with this change was identical to that
produced without this change for the normal case.

So, here is a trivial patch:

- Bhavesh

diff -Naur binutils-2.13.1/bfd/elf.c binutils-bpd/bfd/elf.c
--- binutils-2.13.1/bfd/elf.c	Tue Nov 26 17:46:37 2002
+++ binutils-bpd/bfd/elf.c	Tue Nov 26 17:47:46 2002
@@ -4013,9 +4013,9 @@
       return elf_tdata (abfd)->program_header_size;
-  /* Assume we will need exactly two PT_LOAD segments: one for text
-     and one for data.  */
-  segs = 2;
+  /* Assume we will need many PT_LOAD segments. We will let the second
+     pass truncate the number of PT_LOAD segments if necessary */
+  segs = 10;
   s = bfd_get_section_by_name (abfd, ".interp");
   if (s != NULL && (s->flags & SEC_LOAD) != 0)

Comment 1 Need Real Name 2002-12-02 16:37:32 UTC
Created attachment 87049 [details]
Source file to show bug

Comment 2 Need Real Name 2002-12-02 16:39:53 UTC
Created attachment 87051 [details]
Linker script that shows bug

Comment 3 Jakub Jelinek 2002-12-03 15:01:07 UTC
Not going to happen. This is optimized for the common case.
Your patch wastes 256 bytes at start of every single binary/library (on IA-32,
more so on 64bit arches).
If you need more than 2 PT_LOAD segments, then you just need to make sure
you make more room for it in the linker script.
E.g. by modifying the linker builtin script (ld --verbose), replacing
  /* Read-only sections, merged into text segment: */
  . = 0x08048000 + SIZEOF_HEADERS;
  /* Read-only sections, merged into text segment: */
  . = 0x08048000 + SIZEOF_HEADERS + 256;
(or how much room you want to reserve).

Comment 4 Need Real Name 2002-12-07 02:17:45 UTC
Created attachment 87785 [details]
New patch

Comment 5 Need Real Name 2002-12-07 02:25:13 UTC
The workaround suggested by doesn't work if a linker script is appended to the default linker script (no -T, just a linker script as 
an input file)

However, here is an alternative fix that doesn't reserve additional space for program headers for every ELF binary generated. It only grows the 
program headers if it needs to due to a section definition that requires that a new PT_LOAD segment be created.

Please apply elf.patch

Comment 6 Jakub Jelinek 2004-10-02 20:50:31 UTC
That doesn't work, at the time this routine is invoked, sections
are already sized and thus you can't grow the space for phdrs.
You can always tweak the defaut linker script, as in:
gcc -Wl,--verbose 2>&1 | sed massage_the_script >
gcc ... -Wl,-T, ...

Comment 7 Need Real Name 2004-10-03 16:12:31 UTC
In my case, I already have an elaborate non-standard linker script 
used to generate the executable, which is "appended" to the default 
linker script by specifying the linker script like an input object. 
All I really would like to do is to specify the start of a new 
section at a fixed vaddr, but given the kernel elf loader 
(binfmt_elf) and ld's requirement to have any new section within a 
page of the last one, I needed to allocate a new phdr to do this.

I guess I can always do what you suggest: "gcc -Wl,--verbose 2>&1 | 
massage_the_script > ld_script", but it is adding another layer of 
complexity to an already complex method of generating the linker 
script I have...

And BTW, just so you know, I've been using the elf.patch way of doing 
this by allocating a new phdr *after* all sections have been sized, 
for a 386 MB executable which is our workhorse process for our 
primary telecommunications application at Avaya, and "it just works". 
We haven't hit any issues with "breaking the rules" of assigning a 
new program header this way in the last 2 years of heavy use...

- Bhavesh

Note You need to log in before you can comment on or make changes to this bug.