llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
27.92k stars 11.52k forks source link

[LLD] `EXCLUDE_FILE` linker script directive is not excluding files in linker script rule-matching #100109

Open partaror opened 1 month ago

partaror commented 1 month ago

EXCLUDE_FILE linker script directive is not excluding files in linker script rule-matching.

Reproducible example:

#!/usr/bin/env bash

cat >1.c <<\EOF
int foo() { return 1; }
EOF

cat >2.c <<\EOF
int bar() { return 3; }
EOF

cat >script.t <<\EOF
SECTIONS {
  FOO : { EXCLUDE_FILE(2.o) *(*.text*) }
  BAR : { *(*.text*) }
}
EOF

clang-15 -o 1.o 1.c -c
clang-15 -o 2.o 2.c -c
ld.lld -o a.lld.out 1.o 2.o -T script.t 
ld.bfd -o a.bfd.out 1.o 2.o -T script.t 

Ideally, 1.o(.text) should match FOO output section and 2.o(.text) should match BAR output section. However, when LLD is used, both 1.o(.text) and 2.o(.text) incorrectly matches FOO output section.

Rule-matching is correct when GNU LD is used. (1.o(.text) matches FOO and 2.o(.text) matches BAR)

llvmbot commented 1 month ago

@llvm/issue-subscribers-lld-elf

Author: Parth Arora (partaror)

`EXCLUDE_FILE` linker script directive is not excluding files in linker script rule-matching. Reproducible example: ```bash #!/usr/bin/env bash cat >1.c <<\EOF int foo() { return 1; } EOF cat >2.c <<\EOF int bar() { return 3; } EOF cat >script.t <<\EOF SECTIONS { FOO : { EXCLUDE_FILE(2.o) *(*.text*) } BAR : { *(*.text*) } } EOF clang-15 -o 1.o 1.c -c clang-15 -o 2.o 2.c -c ld.lld -o a.lld.out 1.o 2.o -T script.t ld.bfd -o a.bfd.out 1.o 2.o -T script.t ``` Ideally, `1.o(.text)` should match `FOO` output section and `2.o(.text)` should match `BAR` output section. **However, when LLD is used, both `1.o(.text)` and `2.o(.text)` incorrectly matches `FOO` output section.** Rule-matching is correct when GNU LD is used. (`1.o(.text)` matches `FOO` and `2.o(.text)` matches `BAR`)
smithp35 commented 1 month ago

I've not checked the source code to confirm. This is a drive by comment just in case you are able to update your script. It does seem like all the existing LLD test cases use the EXCLUDE_FILE inside the section list. For example if you rewrite

SECTIONS {
  FOO : { *(EXCLUDE_FILE(2.o) *.text*) }
  BAR : { *(*.text) }
}

Then this will work:

              60               60        b    16 FOO
              60               60        b    16         1.o:(.text)
              60               60        b     1                 foo
              70               70        b    16 BAR
              70               70        b    16         2.o:(.text)
              70               70        b     1                 bar

It may be that LLD isn't correctly implementing the EXCLUDE_FILE before pattern form.

partaror commented 1 month ago

Hi @smithp35,

Thank you for the quick reply. Yes, using EXCLUDE_FILE inside the section patterns list works as expected.

In some cases, it is useful to place EXCLUDE_FILE outside the section patterns list. One example where this is beneficial is described below:

EXCLUDE_FILE(2.o) *(.text.foo .text.bar .text.baz)
*(EXCLUDE_FILE(2.o) .text.foo EXCLUDE_FILE(2.o) .text.bar EXCLUDE_FILE(2.o) .text.baz)

The above two input section descriptions have the same behavior; however, it is much simpler to maintain the input section description with EXCLUDE_FILE outside the section patterns list.