GNU ld's internal linker script uses (https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=add44f8d5c5c05e08b11e033127a744d61c26aee)
.text : { *(.text.unlikely .text.*_unlikely .text.unlikely.*) *(.text.exit .text.exit.*) *(.text.startup .text.startup.*) *(.text.hot .text.hot.*) *(SORT(.text.sorted.*)) *(.text .stub .text.* .gnu.linkonce.t.*) /* .gnu.warning sections are handled specially by elf.em. */ *(.gnu.warning) }
Because *(.text.exit .text.exit.*) is ordered before *(.text .text.*), in a -ffunction-sections build, the C library function exit will be placed before other functions.
gold's -z keep-text-section-prefix has the same problem.
In lld, -z keep-text-section-prefix recognizes .text.{exit,hot,startup,unlikely,unknown}.*, but not .text.{exit,hot,startup,unlikely,unknown}, to avoid the strange placement problem.
In -fno-function-sections or -fno-unique-section-names mode, a function whose function_section_prefix is set to .exit"
will go to the output section .text instead of .text.exit when linked by lld.
To address the problem, append a dot to become .text.exit.