[PATCH] ld: ensure build-id is placed near ELF headers

Andrew Burgess aburgess@redhat.com
Wed Aug 21 10:57:30 GMT 2024


Nick Clifton <nickc@redhat.com> writes:

> Hi Andrew,
>
>    [Sorry for being so late in responding to your email]
>
>> When an executable is built with the --rosegment option GDB is no
>> longer able to find the build-id of the executable from a core file.
>
> For problems like this it really helps if you create a bug report
> using the Sourceware bugzilla system.  This allows us to track the
> problem and any discussion surrounding it.  It also means that we
> can refer to the bug ID in comments in the code.
>
> In order to save you time however, I have gone ahead and created
> a bug report for you:
>
>    https://sourceware.org/bugzilla/show_bug.cgi?id=32100
>
>> This patch aims to fix this by placing the build-id first.  The
>> build-id will then be included within the same LOAD-able segment as
>> the executable content, just as the ELF headers are.  With this patch
>> in place GDB is once again able to find the build-id from a core
>> file.
>
> Unfortunately that patch breaks the intention of the --rosegment
> option by restoring two loadable, read-only segments to the executable.
>
> Here is an example:
>
>    $ cat hello.c
>
>    extern int printf (const char *, ...);
>    int i = 42;
>    const int * j = & i;
>    int main (void) { return printf ("hello world %d\n", * j); }
>
>    $ gcc -fPIC -Wl,-z,noseparate-code hello.c
>    $ readelf -lW a.out | grep LOAD
>
>    LOAD           0x000000 0x0000000000400000 0x0000000000400000 0x0006d4 0x0006d4 R E 0x1000
>    LOAD           0x000df8 0x0000000000401df8 0x0000000000401df8 0x000228 0x000230 RW  0x1000
>
>    $ gcc -fPIX -Wl,-z,separate-code hello.c
>    $ readelf -lW a.out | grep LOAD
>
>    LOAD           0x000000 0x0000000000400000 0x0000000000400000 0x000510 0x000510 R   0x1000
>    LOAD           0x001000 0x0000000000401000 0x0000000000401000 0x000155 0x000155 R E 0x1000
>    LOAD           0x002000 0x0000000000402000 0x0000000000402000 0x0000dc 0x0000dc R   0x1000
>    LOAD           0x002df8 0x0000000000403df8 0x0000000000403df8 0x000228 0x000230 RW  0x1000
>
>    $ gcc -fPIX -Wl,-z,separate-code -Wl,--rosegment hello.c
>    $ readelf -lW a.out | grep LOAD
>
>    LOAD           0x000000 0x0000000000400000 0x0000000000400000 0x00115d 0x00115d R E 0x1000
>    LOAD           0x002000 0x0000000000402000 0x0000000000402000 0x0002d4 0x0002d4 R   0x1000
>    LOAD           0x002df8 0x0000000000403df8 0x0000000000403df8 0x000220 0x000228 RW  0x1000
>
>    $ gcc -fPIX -Wl,-z,separate-code -Wl,--rosegment hello.c -fuse-ld=patched-linker
>    $ readelf -lW a.out | grep LOAD
>
>    LOAD           0x000000 0x0000000000400000 0x0000000000400000 0x00039c 0x00039c R   0x1000
>    LOAD           0x001000 0x0000000000401000 0x0000000000401000 0x00015d 0x00015d R E 0x1000
>    LOAD           0x002000 0x0000000000402000 0x0000000000402000 0x00024c 0x00024c R   0x1000
>    LOAD           0x002df8 0x0000000000403df8 0x0000000000403df8 0x000220 0x000228 RW  0x1000
>
>    (I invented the "-fuse-ld=patched-linker" option to keep the presentation simple.  In
>    reality I used a full path to a linker built with your proposed patch applied).
>
> The section to segment mapping is changed by using --rosegment, but with your patch
> applied we still get an early read-only segment containing the note sections.
>
> I think that what is needed is a patch to move all of the read-only segments to
> before the read-execute segment.  But this weill need testing.

Thanks for taking the time to test this patch.  Sorry that this failed.
I had thought I'd seen different results, but retesting I can reproduce
what you see, so clearly I was doing something wrong before[1].

I do have one question which you might be able to enlighten me on
though: the initial loadable segment contains both the code, but also
the ELF headers, right?  Which are clearly not executable content.

So it would seem that it is OK to have a limited set of data mapped at
the start of the code segment.  Clearly we don't want _all_ the data
placed there as that would make the separate segments pointless.  But
something that is not usually read by the program itself (e.g. ELF
headers, or the build-id) seemed OK.

My next question then would be, I guess the linker is creating a new
segment because the permissions of the build-id section doesn't match
that of the code section.  Instead of moving all the sections, can the
linker be told/convinced to merge the build-id into the start of the
code?

I'm just trying to understand more about how this all works.

Thanks,
Andrew


[1] I'm pretty sure I figured out what I was doing wrong.  But it was a
stupid error my side.

>
> Cheers
>    Nick



More information about the Binutils mailing list