Skip to main content

LinkLine

Struct LinkLine 

Source
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

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Trait Implementations§

Source§

impl Clone for LinkLine

Source§

fn clone(&self) -> LinkLine

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for LinkLine

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for LinkLine

Source§

impl PartialEq for LinkLine

Source§

fn eq(&self, other: &LinkLine) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for LinkLine

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.