Semantics of a common definition in an archive

Fangrui Song i@maskray.me
Tue Aug 18 04:46:40 GMT 2020


I am playing with common definitions in an archive and have noticed a strange
property.

>a.s echo '.globl _start; _start: call foo'
>b.s echo '.globl foo; foo: .common var,4,4'
>c.s echo '.globl foo; foo: .data; .globl var; var:'
>d.s echo '.globl foo; foo: .common var,8,8'

gcc -c a.s b.s c.s d.s
ar rc b.a b.o
ar rc c.a c.o
ar rc d.a d.o


The archive index of c.a says c.o defines var.  It seems that ld is not
satisfied with the common definition in b.a(b.o) and checks whether c.a(c.o)
provides a regular definition. It does, so GNU ld pulls c.a(c.o) and errors
for the multiple definition of foo.

ld.bfd a.o b.a c.a
# ld.bfd: c.a(c.o): in function `foo':
# (.text+0x0): multiple definition of `foo'; b.a(b.o):(.text+0x0): first defined here
# ld.bfd: warning: alignment 1 of symbol `var' in c.a(c.o) is smaller than 4 in b.a(b.o)

Gold and LLD's semantics are different.

gold a.o b.a c.a   # succeeded. c.a(c.o) is not pulled.
ld.lld a.o b.a c.a # succeeded


ld does not pull d.a(d.o) because it provides a common definition, not better
than the common definition in b.a(b.o). Though the archive member is inspected,
align/size fields are not updated.

ld.bfd a.o b.a d.a
# good.
readelf -Ws a.out | grep var  # align=size=4; The common definition in d.a(d.o) is ignored
#      5: 0000000000402000     4 OBJECT  GLOBAL DEFAULT    2 var

-----

So, are the GNU ld behaviors described above all desired?  Apparently, when a
symbol in the archive index is currently common, ld does not treat it as "ground
truth". This behavior appears to be quite unusual. I think the documentation
should probably be improved to mention the desired behaviors.

(GCC 10 and clang 11 default to -fcommon for C. In Fortran, IIUC FORTRAN 77 uses
COMMON blocks. Fortran 90 does not recommend COMMON. These issues may become
less and less relevant over time.)


More information about the Binutils mailing list