My question is: given a link line of ld.lld [...] a.o b.o c.o, when should one expect the .text section of each object to be laid out in a, b, c, order in the resulting library or binary (if ever)? Conversely, when should one not expect link line order to be maintained?
A fairly standard .text specification. The key is that FreeBSD depends on the aforementioned function btext, defined in locore.S, to begin the text section. And as far as I can tell, the only thing enforcing this required behavior to boot is that locore.o is specified as the first object in the link line:
One (but potentially not the only one) way to reorder the sections is the linker script. The linker script could be modified to explicitly require, say, .text contributions from a file with a specific name to appear before other such files. Chances are that if you look at your .ctors/.dtors sections in the script, you’ll see such a case involving CRT files, but basically the * outside the brackets for one of those lines in the script means “any file” and can be replaced with an input file name to say “from files named this”. For example, the following linker script snippet would place .text sections from “foo.o” before those from other objects (input order defined), and then finally “bar.o” contributions:
There is one line in the GNU linker script documentation, which LLD generally follows in Input Section Wildcards (LD)
Normally, the linker will place files and sections matched by wildcards in the order in which they are seen during the link. You can change this by using the SORT_BY_NAME keyword, which appears before a wildcard pattern in parentheses (e.g., SORT_BY_NAME(.text*) ). When the SORT_BY_NAME keyword is used, the linker will sort the files or sections into ascending order by name before placing them in the output file.
There are special cases for certain types of sections, for example sections with SHF_MERGE but this shouldn’t apply to .text.
Although the document doesn’t word the order as a requirement, in practice I think too many programs depend on it for a linker to arbitrarily change it, at least not for the default options. For example there is a --symbol-ordering-file=<value> option that can alter the layout to match the file, however that is a user supplied option.
Trade offs for a locore.o(.text) input section wildcard pattern are:
It is more explicit than relying on the ordering within .text, as the linker is required to put wildcard patterns file1(section1)file2(section2) in order. (Input Section Basics (LD))
It is more fragile to changes in file or section name. For example if locore.o changes its name.
Yes, thank you. This is a much more common example of an ordering requirement. And, combining examples, this is important enough that the FreeBSD kernel linker script explicitly spells it out for .ctors/.dtors.
Thanks, this clarifies things for me.
After reading these responses and examining the source further, my understanding is now that lld will layout following the object file order convention unless:
Specified otherwise in the linker script, which can be done in several ways (at a minimum, see responses from @jh7370 and @smithp35)
--symbol-ordering-file=<value> is specified by the user
In some situations, if .text variant sections (.text.hot, .text.unlikely, etc.) are present in the object files
This is not for the reason you state it is. It spells it out because it needs to sort the contents of .ctors in the linker script, and it has to use SORT on the numbered .ctors.* inserted in the middle of .ctors. This is why .ctors is special.