[Patch] ld: Fix string merging origin symbol address

Michael Matz matz@suse.de
Tue Apr 8 12:52:35 GMT 2025


Hello,

On Mon, 7 Apr 2025, Guillaume VACHERIAS - foss wrote:

> What I wanted to point out was not a problem on the resolved address in 
> the final binary itself, which is correct, but rather on the information 
> that the map file generates. After the optimization of string merging 
> contributions (1a528d3ef07fc6084fc51759c1b2f8abb5c8127e), the 
> information generated by the map file is less precise.

Ah, I see.  IIRC, I alluded to that somewhat in my mail for that patch.  

FWIW, I don't consider it a good tradeoff to use a pointer entry for each 
string pointing back to the original section info it came from just for 
generating a different Map file.  These entries tend to become fairly 
large on bigger testcases.

Also, does it even work in the current state?  Emitting only strings from 
a certain input section like you do in sec_merge_emit requires that they 
are also sorted primarily in that way.  That logic seems to partly come 
from before my patch and that whole dealing with individual secinfos gave 
me headaches already back then.  I wholeheartedly suggest to not 
re-introduce it again, and if possible rather get rid of more of their use 
(some of the asserts I added point into that direction, though I haven't 
followed through with that).

> More specifically, the map file can no longer provide the address where 
> a string from an input section .rodata is in the final binary.

And it generally can't in the case of merged sections.  I think it's 
futile to try and give the impression that it could when it really cannot.

> Taking the testcase that I've added as an example. The only mergeable 
> string would be "i" since it is the suffix of "ghi" and everything else 
> is different. However, when we run the testcase with current string 
> merge, it results in the following map file:
> 
> .rodata         0x00000000        0xc
>  *(.rodata*)
>  .rodata.foo.str1.1
>                 0x00000000        0xc tmpdir/rodata-merge-map-address1.o
>                                   0x4 (size before relaxing)
>  .rodata.bar.str1.1
>                 0x0000000c        0x4 tmpdir/rodata-merge-map-address2.o
>  .rodata.baz.str1.1
>                 0x0000000c        0x6 tmpdir/rodata-merge-map-address3.o
> 
> The string merging mechanism makes it as the very first object file 
> contains all strings, the .rodata.foo.str1.1 indicates that its length 
> is 0xc where it was supposed to be only 0x4 as it only contributes 
> "abc". This results in that the other 2 sections .rodata.bar.str1.1 and 
> .rodata.bar.str1.1 seems to be placed at the end of of the .rodata 
> section.

Well, that is what conceptually happens.  As the original sections 
contents are completely mixed up in the final blob, including being 
arbitrarily reordered, completely removed, or tucked somewhere into the 
middle, the original sections aren't placed anywhere specifically.  We 
could say "merged into ..." or something like that, but saying it has an 
address A and size S in the final result is always wrong except in the 
simplest testcases that don't merge much or anything.  Claiming it has an 
address and a size means claiming that its contents are consecutive in the 
result, which isn't generally true.

That the whole blob is regarded as belonging to the first of mergable 
sections is a wart, but that's what the bfd linker generally does: even 
linker generated sections "belong" to the first input file in many cases.

The only thing that I think would be left to improve in the above Mapfile 
output is the size after relaxing of the other input sections: 
make them all zero.  Then the given information in the map file adds up 
and it correctly captures the concept of all sections contents to be going 
through a special process and be completely subsumed by it.

> The correct map file information that used to be generated which also 
> indicates that "i" has been merged is:
> 
> .rodata         0x00000000        0xc
>  *(.rodata*)
>  .rodata.foo.str1.1
>                 0x00000000        0x4 .*rodata-merge-map-address1.o
>  .rodata.bar.str1.1
>                 0x00000004        0x4 .*rodata-merge-map-address2.o
>  .rodata.baz.str1.1
>                 0x00000008        0x4 .*rodata-merge-map-address3.o
>                                   0x6 (size before relaxing)

I think its only superficially "more correct".

Can I ask you why you want that info in the Map file to be better?  What 
do you do with it, and how comes that whatever that is doesn't break in 
more complicated testcases that do merge a number of meaningful entries?


Ciao,
Michael.


More information about the Binutils mailing list