Question about deduplication of COMDAT sections with different alignment

Jens Remus jremus@linux.ibm.com
Wed May 21 15:16:11 GMT 2025


Hello Alan,

thank you for your feedback!

On 21.05.2025 01:40, Alan Modra wrote:
> On Tue, May 20, 2025 at 03:49:36PM +0200, Jens Remus wrote:
>> Shouldn't section .rodata in both sample-12 and sample-21 better have a
>> 2-byte alignment, regardless of which instance of COMDAT section group
>> foo_group got deduplicated?  After all code in foo-2.o (not part of this
>> example) may rely on foo being 2-byte aligned.
> 
> I don't bellieve there is any requirement to keep alignment or other
> attributes of discarded groups.  If code in foo-2.o that depends on
> alignment of the data is part of the group then it will be discarded
> along with the data.  If it is not part of the group then I'd guess
> you have a programming or compiler error.

Hmm, something I did not consider and seemed very logical at first.  But
C++ compilers, at least on S390, apparently do not put code depending on
the alignment and read-only data into a COMDAT group.  Following is my
attempt at a (rather lengthy) minimal example, that fails to build on
S390 even without any linker GOT access relaxations involved:



$ cat sample_cpp.sh
#!/bin/bash
set -u -x

CXX_GCC="${CXX_GCC:-g++}"
CXX_CLANG="${CXX_CLANG:-clang++}"
CXX=$CXX_GCC
CXXFLAGS="-fPIE ${EXTRA_CXXFLAGS:--O1}"
LDFLAGS="-Wl,-pie"
READELF="${READELF:-readelf}"
OBJDUMP="${OBJDUMP:-objdump}"

cat <<EOF > foo.cpp
#include <typeinfo>
struct A {};
const bool foo(const std::type_info &ti) { return typeid(A) == ti; }
EOF

cat <<EOF > bar.cpp
#include <typeinfo>
struct A {};
struct B {};
const std::type_info &ti_b = typeid(B);
const bool bar(const std::type_info &ti) { return typeid(A) == ti; }
EOF

cat <<EOF > main.cpp
#include <typeinfo>
extern const std::type_info &ti_b;
extern const bool foo(const std::type_info &ti);
extern const bool bar(const std::type_info &ti);
int main (int argv, char *argc[])
{
  if (foo (ti_b));
    return 1;
  if (bar (ti_b));
    return 2;
  return 0;
}
EOF

$CXX_GCC $CXXFLAGS -c -o foo_gcc.o foo.cpp
$CXX_CLANG $CXXFLAGS -c -o bar_clang.o bar.cpp
$CXX $CXXFLAGS -c -o main.o main.cpp
$CXX $LDFLAGS -o sample-21 main.o foo_gcc.o bar_clang.o
$CXX $LDFLAGS -o sample-12 main.o bar_clang.o foo_gcc.o
$READELF -WS foo_gcc.o bar_clang.o sample-12 sample-21 | grep -E "File:|\[Nr\]| \.rodata"
$OBJDUMP -dr foo_gcc.o
$OBJDUMP -dr bar_clang.o



$ PATH=$HOME/temp/binutils-master/bin:$PATH ./sample_cpp2.sh
...
+ g++ -fPIE -O1 -c -o foo_gcc.o foo.cpp
+ clang++ -fPIE -O1 -c -o bar_clang.o bar.cpp
+ g++ -fPIE -O1 -c -o main.o main.cpp
+ g++ -Wl,-pie -o sample-21 main.o foo_gcc.o bar_clang.o
+ g++ -Wl,-pie -o sample-12 main.o bar_clang.o foo_gcc.o
/home/jremus/temp/binutils-master/bin/ld: foo_gcc.o(.text+0x8): relocation R_390_PC32DBL against misaligned symbol `_ZTS1A' (0x963) in bar_clang.o
/home/jremus/temp/binutils-master/bin/ld: final link failed
collect2: error: ld returned 1 exit status
+ readelf -WS foo_gcc.o bar_clang.o sample-12 sample-21
+ grep -E 'File:|\[Nr\]| \.rodata'
readelf: Error: 'sample-12': No such file
File: foo_gcc.o
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 6] .rodata._ZTS1A    PROGBITS        0000000000000000 0000a8 000004 00  AG  0   0  2
File: bar_clang.o
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 5] .rodata._ZTS1B    PROGBITS        0000000000000000 00008e 000003 00  AG  0   0  1
  [12] .rodata._ZTS1A    PROGBITS        0000000000000000 0000b0 000003 00  AG  0   0  1   <-- !
File: sample-21
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [14] .rodata           PROGBITS        000000000000095c 00095c 00000b 00   A  0   0  4
...
foo_gcc.o:     file format elf64-s390
...
0000000000000000 <_Z3fooRKSt9type_info>:
   0:   e3 10 20 08 00 04       lg      %r1,8(%r2)
   6:   c0 20 00 00 00 00       larl    %r2,6 <_Z3fooRKSt9type_info+0x6>   <-- !
                        8: R_390_PC32DBL        _ZTS1A+0x2
...



The larl %r2,_ZTS1A emitted by GCC clashes with the Clang emitted
.rodata._ZTS1A CPMDAT section alignment of 1.

For the time being we came to the conclusion that Clang is violating the
s390x (64-bit) ELF ABI, as it does not take the necessary precautions to
ensure that the _ZTS1A symbol value ends up 2-byte aligned.  Something
we are going to fix.

Nevertheless I think the above example still shows a valid case where
code emitted by a compiler depends on its own specific COMDAT section
alignment.  Each compiler emitted code works with its own alignment,
but may fail with a lesser alignment.

Regards,
Jens
-- 
Jens Remus
Linux on Z Development (D3303)
+49-7031-16-1128 Office
jremus@de.ibm.com

IBM

IBM Deutschland Research & Development GmbH; Vorsitzender des Aufsichtsrats: Wolfgang Wendt; Geschäftsführung: David Faller; Sitz der Gesellschaft: Böblingen; Registergericht: Amtsgericht Stuttgart, HRB 243294
IBM Data Privacy Statement: https://www.ibm.com/privacy/



More information about the Binutils mailing list