pub struct LinkLine {
pub start: Vec<PathBuf>,
pub libraries: Vec<PathBuf>,
pub end: Vec<PathBuf>,
}Expand description
The inputs to a link, in the three groups a linker needs them in.
Paths rather than strings, and no flags at all, because
spec/cross-compile/11-linking.md owns which linker is invoked and how its arguments are
spelled and crate::argv is where that happens. What is here is what has to be linked and in
what order, which is a target fact and the same fact whichever linker reads it.
Fields§
§start: Vec<PathBuf>The start files, before the user’s objects.
libraries: Vec<PathBuf>The libraries, after the user’s objects.
end: Vec<PathBuf>The end files, after the libraries.
Implementations§
Source§impl LinkLine
impl LinkLine
Sourcepub fn for_target(sysroot: &Sysroot, mode: LinkMode) -> Self
pub fn for_target(sysroot: &Sysroot, mode: LinkMode) -> Self
The line for a link against this sysroot, whichever libc the target names.
The dispatch rather than the line, and it is libc that decides: a real archive, a stub
shared object, or nothing. The three methods below are the three answers. A target whose
sysroot we do not produce yet still gets the right shape, because the shape follows from
whether the libc on the target machine is an archive or a shared object and that is known
before any of it is built.
Sourcepub fn freestanding(sysroot: &Sysroot) -> Self
pub fn freestanding(sysroot: &Sysroot) -> Self
The line for a freestanding link against this sysroot, which is our runtime and nothing else.
Section 8.2’s first row: nine compiler headers and no link inputs. There is no crt1.o,
because nothing here decides what runs before main or whether there is a main at all, and
no crti.o or crtn.o, because those come from a libc too. A kernel or a bootloader brings
its own start file and says so with -nostartfiles, which it would have to pass anyway.
librucc_builtins.a stays, because it is ours rather than the platform’s.
spec/cross-compile/10-runtime.md is the argument: an architecture with no division
instruction needs __divti3 whether there is a libc in the picture or not, and freestanding
code that does 64-bit arithmetic on a 32-bit target reaches it without asking.
The mode is not a parameter because it changes nothing here. Every difference between the modes is a start file and there are none.
Sourcepub fn musl(sysroot: &Sysroot, mode: LinkMode) -> Self
pub fn musl(sysroot: &Sysroot, mode: LinkMode) -> Self
The line for a musl link against this sysroot.
crt1.o runs before main and calls it. crti.o and crtn.o are the prologue and the
epilogue of the .init and .fini sections, which is why one is at the front and the other
is at the very back. libc.a carries musl’s whole C library, and librucc_builtins.a
carries the operations the architecture does not have an instruction for, which
spec/cross-compile/10-runtime.md says has to be ours rather than the platform’s.
The builtins go after libc.a because musl calls some of them, and an archive that is
searched before the thing that needs it contributes nothing.
libc.a on every mode including the dynamic ones, because what a musl sysroot here holds is
musl built static: section 9.3 takes musl first precisely because one tarball built one way
exercises the whole pipeline, and a shared musl is a second build of it that buys nothing
until somebody asks for a dynamically linked musl program.
Sourcepub fn glibc(sysroot: &Sysroot, mode: LinkMode) -> Self
pub fn glibc(sysroot: &Sysroot, mode: LinkMode) -> Self
The line for a link against a generated stub, which is glibc and every other hosted libc that is not musl.
Named for glibc because glibc is the case spec/cross-compile/09-libc-stubs.md is written
about and the hard one. bionic, the BSDs and illumos reach the same line for the same reason:
their libc is a shared object on the target machine, so a list of the names it exports is
enough to link against it, and that is what rucc-stub produces. The paragraphs below about
libc_nonshared.a and libm are glibc’s own.
The same start files as musl’s and a different library, and the library is the whole
difference between them here. A stub libc is linked against dynamically, so what goes on the
line is the generated libc.so from rucc-stub rather than an archive, and the version nodes
in it are what make a program built here run on an older machine.
libc_nonshared.a is deliberately absent and it is a known gap rather than a decision.
glibc’s own libc.so is a linker script naming libc.so.6, libc_nonshared.a and the
loader as a group, and that archive holds real compiled objects: atexit, __stack_chk_fail_local
on i386, and the stat family on releases before 2.33. None of it can be synthesized from a
description, because a stub is a list of names and these are bodies, so it has to be built
from glibc’s sources and that is M9.5’s work. A program that needs nothing from it links
today and a program that does gets an undefined symbol, which is the loud failure rather
than the quiet one.
libm.so is not here either, and that is a decision. glibc’s libm is real code and a
program that wants it passes -lm, which every build system that does arithmetic already
does, so putting it on every line would record a dependency the program does not have.
A static glibc link is not one of these: there is no libc.a in a sysroot whose libc is a
stub, because a stub is a list of names and a static link needs bodies.
crate::argv::argv refuses that combination by name rather than producing this line with
-static in front of it.
Sourcepub fn mingw(sysroot: &Sysroot, mode: LinkMode) -> Self
pub fn mingw(sysroot: &Sysroot, mode: LinkMode) -> Self
The line for a mingw-w64 link against this sysroot.
One start file and no end file, which is the first thing that is different from every ELF
line above. crt2.o runs before main and calls it, dllcrt2.o is its counterpart for a
DLL, and there is no crti.o and no crtn.o because PE has no .init and .fini sections
for a pair of files to open and close. What those two bracket on ELF is done on Windows by a
table of pointers in the .CRT$XC sections, which the linker sorts by section name, so the
ordering problem the three groups exist for does not arise here.
crtbegin.o and crtend.o are deliberately absent. They are GCC’s files rather than
mingw-w64’s, they bracket GCC’s own list of constructors, and a toolchain that is not GCC
writes that list the way the platform writes it instead. Ours is not written yet: a mingw
link runs main and does not run a file scope constructor, which is a known gap that belongs
with the sysroot build rather than with the line, and the gap is in the codegen for the
format rather than here.
The libraries are a set rather than one file, because the C library on Windows is several
DLLs and the CRT calls into the system ones. libmingw32.a holds the start code crt2.o
calls, libmoldname.a is the layer that gives the old unprefixed spellings of the names
Microsoft deprecated, libmingwex.a is everything C requires that msvcrt does not have, and
libmsvcrt.a is the import library for the CRT itself. Then the four Win32 libraries that
mingw-w64’s own code calls into, which are on the line for the same reason they are on gcc’s:
a program that uses none of them directly still reaches kernel32 through malloc.
The order is the one a single pass linker needs, which is GNU ld’s PE port: a library after
everything that calls into it. librucc_builtins.a is last for the reason it is last on the
musl line, which is that the things before it call it and it calls none of them. lld’s COFF
linker resolves archives to a fixed point and does not care about any of this, and writing
the line for the stricter of the two is what makes one line serve both.
Sourcepub fn with_objects(&self, objects: &[PathBuf]) -> Vec<PathBuf>
pub fn with_objects(&self, objects: &[PathBuf]) -> Vec<PathBuf>
Every input, in the order they reach the linker, with the caller’s objects in the middle.
The one function that knows the whole order, so that a caller cannot assemble the three groups in the wrong sequence.