gas: copy st_size only if unset
authorFangrui Song <i@maskray.me>
Mon, 4 Apr 2022 15:43:50 +0000 (08:43 -0700)
committerFangrui Song <maskray@google.com>
Mon, 4 Apr 2022 15:43:50 +0000 (08:43 -0700)
commit867b8c308a40e79f90db4051cafc273f00f881fb
treea7c39c1860484bf1064db52fbdd2b340d2181036
parentedbc15e6c4f463173b25b1f8042346c2e1a78602
gas: copy st_size only if unset

For
```
.size foo1, 1
foo1:

.set bar1, foo1
.size bar1, 2
.size bar2, 2
.set bar2, foo1

.set bar3, foo2
.size bar3, 2
.size bar4, 2
.set bar4, foo2

.size foo2, 1
foo2:
```

bar1's size is 2 while bar2, bar3, bar4's is 1. The behavior of bar1 makes sense
(generally directives on the new symbol should win) and is relied upon by glibc
stdio-common/errlist.c:

```
        .hidden _sys_errlist_internal
        .globl  _sys_errlist_internal
        .type   _sys_errlist_internal, @object
        .size   _sys_errlist_internal, 1072
_sys_errlist_internal:

        .globl __GLIBC_2_1_sys_errlist
        .set __GLIBC_2_1_sys_errlist, _sys_errlist_internal
        .type __GLIBC_2_1_sys_errlist, %object
        .size __GLIBC_2_1_sys_errlist, 125 * (64 / 8)

// glibc expects that .size __GLIBC_2_1_sys_errlist, 125 * (64 / 8) wins.
```

The behavior of bar2/bar3/bar4 seems brittle. To avoid the reordering of the two
code blocks which will result in the bar3 situation, glibc compiles errlist.c
with gcc -fno-toplevel-reorder (previously -fno-unit-at-a-time).

To fix the inconsistency and improve robustness, make bar2/bar3/bar4 match bar1,
removing the directive order sensitivity.

There is a pity that `.size dest, 0` is indistinguishable from the case where
dest is unset, but the compromise seems fine.

    PR gas/29012
    * config/obj-elf.c (elf_copy_symbol_attributes): don't copy if src's size
      has been set.
    * testsuite/gas/elf/elf.exp: New test.
    * testsuite/gas/elf/size.d: New file.
    * testsuite/gas/elf/size.s: Likewise.
gas/config/obj-elf.c
gas/testsuite/gas/elf/elf.exp
gas/testsuite/gas/elf/size.d [new file with mode: 0644]
gas/testsuite/gas/elf/size.s [new file with mode: 0644]