Bug 78871 - bfd/elf allows only 2 PT_LOAD segments/phdrs
bfd/elf allows only 2 PT_LOAD segments/phdrs
Status: CLOSED WONTFIX
Product: Red Hat Linux
Classification: Retired
Component: binutils (Show other bugs)
8.0
i686 Linux
high Severity high
: ---
: ---
Assigned To: Jakub Jelinek
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2002-12-02 11:35 EST by Need Real Name
Modified: 2005-10-31 17:00 EST (History)
1 user (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2004-10-02 16:50:31 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)
Source file to show bug (134 bytes, text/plain)
2002-12-02 11:37 EST, Need Real Name
no flags Details
Linker script that shows bug (51 bytes, text/plain)
2002-12-02 11:39 EST, Need Real Name
no flags Details
New patch (998 bytes, patch)
2002-12-06 21:17 EST, Need Real Name
no flags Details | Diff

  None (edit)
Description Need Real Name 2002-12-02 11:35:34 EST
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)
    {
      ((*_bfd_error_handler)
       (_("%s: Not enough room for program headers (allocated %u, need
%u)"),
        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:
Always

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

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:

Thanks!
- 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 11:37:32 EST
Created attachment 87049 [details]
Source file to show bug
Comment 2 Need Real Name 2002-12-02 11:39:53 EST
Created attachment 87051 [details]
Linker script that shows bug
Comment 3 Jakub Jelinek 2002-12-03 10:01:07 EST
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;
with
  /* 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-06 21:17:45 EST
Created attachment 87785 [details]
New patch
Comment 5 Need Real Name 2002-12-06 21:25:13 EST
The workaround suggested by jakub@redhat.com 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 16:50:31 EDT
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 > prog.lds
gcc ... -Wl,-T,prog.lds ...
Comment 7 Need Real Name 2004-10-03 12:12:31 EDT
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...

Thanks
- Bhavesh

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