Skip to content

Instantly share code, notes, and snippets.

@ikskuh
Created March 19, 2021 00:02
Show Gist options
  • Save ikskuh/65e7a158a600a94dad22ab5a15be080f to your computer and use it in GitHub Desktop.
Save ikskuh/65e7a158a600a94dad22ab5a15be080f to your computer and use it in GitHub Desktop.
linkerscript.zig
const std = @import("std");
/// The linker here is "preloaded" with all input object files / symbols.
/// After this function is run, the linker will resolve all symbol references
/// and print all unassigned symbols (\u2192 error)
pub fn link(l: *std.link.Linker) !void {
// Creates a new output section that will be loaded into the
// same address as its virtual address. It's also a (rx!w) section
const dot_text = l.createOutputSection(".text", .{
.read = true,
.execute = true,
.write = false,
.load_address = .virtual_address,
.virtual_address = 0x0000_0000,
});
{
// Search all symbols that match a given filter (in this case "are in section .text")
var iter = l.findSymbols(.{ .section = ".text" });
while (iter.next()) |sym| {
dot_text.append(sym);
}
}
// Assert we have at least our first 8 interrupt vectors
std.debug.assert(dot_text.length > 8 * 4);
// Compute the checksum in the interrupt vector table,
// this is an inplace modification of the section data
{
var checksum: u32 = 0;
var i: usize = 0;
while (i < 7) : (i += 1) {
checksum -%= std.mem.readIntLittle(u32, dot_text.data[4 * i ..][0..4]);
}
std.mem.writeIntLittle(u32, dot_data.data[28..32], checksum);
}
// Put .data behind .text in the flash memory
// This section will be loaded into a different memory area than the one it is linked to.
const dot_data = l.createOutputSection(".data", .{
.read = true,
.execute = false,
.write = true,
.load_address = .{ .fixed = dot_text.length }, // Load the .data section directly behind .text into flash
.virtual_address = 0x1000_0000,
});
// Same as the loop above, will just add all symbols that match the filter
dot_data.appendAll(.{ .section = ".data" });
// Assert that .text + .data fit in the flash and don't exceed total flash size
std.debug.assert(dot_text.length + dot_data.length <= 512 * 1024);
// Put .data behind .text in the flash memory
const dot_bss = l.createOutputSection(".bss", .{
.read = true,
.execute = false,
.write = true,
.load_address = .zero_init, // Sets the section to not be loaded in the final artifact (zero init)
.virtual_address = dot_data.virtual_address + dot_data.length, // Section is located *behind* .data
});
// Same as the loop above, will just add all symbols that match the filter
dot_bss.appendAll(.{ .section = ".bss" });
// Assert that .text + .bss fit into the lower RAM
std.debug.assert(dot_data.length + dot_bss.length < 32 * 1024);
// Set/store our entry point in the output file
if (l.findSymbol("_start")) |sym| {
l.setEntryPoint(sym.address.?);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment