Closed kees closed 5 years ago
Fixed in https://reviews.llvm.org/rL369889.
Proposed patch: https://reviews.llvm.org/D66279
In this case, and I think llvm/llvm-project#41851 which is strongly related, LLD is evaluating the expression of symbol assignment too eagerly. In effect at the time efistubend = _end; is read in, it will be evaluated, losing any later changes made to the value of _end.
The best that I can find in the documentation about what is supposed to happen is: https://sourceware.org/binutils/docs/ld/Evaluation.html#Evaluation but it isn't explicit about this case.
In BFD ldlang.c there is a late run of just the symbol assignments after Section sizes have been fixed lang_do_assignments (lang_final_phase_enum). This would mean that _end would have its final value.
I think LLD will need something like a late pass through just the symbol assignements to update aliases. Ideally we'd be able to make something that would solve the outstanding symbol definition differences in one go.
Actually, llvm/llvm-project#41851 appears to be solved with the same workaround as here. (Though they still may be different bugs.)
Also, FWIW, this bug appears to be distinct from these seemingly related issues:
llvm/llvm-project#40514
llvm/llvm-project#41851
This is from https://github.com/ClangBuiltLinux/linux/issues/634
Extended Description
The following poc.lds links differently between bfd and lld:
efistubend = _end; SECTIONS { . = 0xffff; . += ((_end >> 8) - 0xff ); _end = .; }
Linking with an empty .o file:
$ ld.lld -maarch64elf -shared -o vmlinux.lld -T poc.lds /tmp/test.o && readelf -Ws vmlinux.lld | egrep '\b(init_pg_size|(efistub_|)_end)\b' 2: 000000000000ffff 0 NOTYPE GLOBAL DEFAULT 1 _end 3: 000000000000ff00 0 NOTYPE GLOBAL DEFAULT 1 efistubend
i.e. efistubend is calculated before _end is known. Moving the efistubend assignment to after the SECTIONS {} works around this bug.
bfd produces the same results with either ordering:
$ aarch64-linux-gnu-ld.bfd -maarch64elf -shared -o vmlinux.bfd -T poc.lds /tmp/test.o && readelf -Ws vmlinux.bfd | egrep '\b(init_pg_size|(efistub_|)_end)\b' 2: 000000000000ffff 0 NOTYPE GLOBAL DEFAULT 1 _end 4: 000000000000ffff 0 NOTYPE GLOBAL DEFAULT ABS efistubend