lib/std/arch/rv64/shared/catalog.rad 6.0 KiB raw
1
//! Persistent native boot catalogs for the RV64 record ABI.
2
3
use std::mem;
4
use std::arch::rv64::shared;
5
6
/// Binary package identity and its resident native descriptor.
7
export record Entry: Copy {
8
    /// Complete immutable binary RIL bytes.
9
    source: *[u8],
10
    /// Shared code, exports, and private-state template.
11
    package: shared::Package,
12
}
13
14
/// Reserve aligned bytes in the native catalog output.
15
fn reserve(output: &mut [u8], used: &mut u32, size: u32, alignment: u32) -> u32 throws (shared::Error) {
16
    let padding = (alignment - (*used & (alignment - 1))) & (alignment - 1);
17
    if padding > output.len - *used { throw shared::Error::Capacity; }
18
    let offset = *used + padding;
19
    if size > output.len - offset { throw shared::Error::Capacity; }
20
    for i in *used..offset { set output[i] = 0; }
21
    set *used = offset + size;
22
    return offset;
23
}
24
25
/// View the native bytes of a caller-owned record or array.
26
unsafe fn raw(value: &opaque, size: u32) -> *unsafe [u8] { return @sliceOf((value as &u8) as *unsafe u8, size); }
27
28
/// Obtain a field's byte offset from the compiler's native record layout.
29
unsafe fn field(container: &opaque, value: &opaque) -> u32 { return (value as u64 - container as u64) as u32; }
30
31
/// Write one little-endian integer into a reserved native field.
32
fn integer(output: &mut [u8], offset: u32, value: u64, width: u32) {
33
    for i in 0..width { set output[offset + i] = (value >> (i as u64 * 8)) as u8; }
34
}
35
36
/// Write the RV64 pointer, length, and capacity of a native immutable slice.
37
fn slice(output: &mut [u8], offset: u32, address: u64, length: u32) {
38
    integer(output, offset, address, 8);
39
    integer(output, offset + 8, length as u64, 4);
40
    integer(output, offset + 12, length as u64, 4);
41
}
42
43
/// Copy bytes into the catalog and return their target-relative offset.
44
fn bytes(input: *[u8], output: &mut [u8], used: &mut u32) -> u32 throws (shared::Error) {
45
    let offset = try reserve(output, used, input.len, 1);
46
    try! mem::copy(&mut output[offset..offset + input.len], input);
47
    return offset;
48
}
49
50
/// Copy a dependency list and each name into native catalog storage.
51
unsafe fn dependencies(input: *unsafe [*[u8]], base: u64, output: &mut [u8], used: &mut u32) -> u32 throws (shared::Error) {
52
    if input.len > output.len / @sizeOf(*[u8]) { throw shared::Error::Capacity; }
53
    let offset = try reserve(output, used, input.len * @sizeOf(*[u8]), @alignOf(*[u8]));
54
    for name, i in input {
55
        let at = try bytes(name, output, used);
56
        slice(output, offset + i * @sizeOf(*[u8]), base + at as u64, name.len);
57
    }
58
    return offset;
59
}
60
61
/// Copy public symbols and their names into native catalog storage.
62
unsafe fn symbols(input: *[shared::Symbol], base: u64, output: &mut [u8], used: &mut u32) -> u32 throws (shared::Error) {
63
    if input.len > output.len / @sizeOf(shared::Symbol) { throw shared::Error::Capacity; }
64
    let offset = try reserve(output, used, input.len * @sizeOf(shared::Symbol), @alignOf(shared::Symbol));
65
    for symbol, i in input {
66
        let at = offset + i * @sizeOf(shared::Symbol);
67
        try! mem::copy(&mut output[at..at + @sizeOf(shared::Symbol)], raw(&symbol, @sizeOf(shared::Symbol)));
68
        let name = try bytes(symbol.name, output, used);
69
        slice(output, at + field(&symbol, &symbol.name), base + name as u64, symbol.name.len);
70
    }
71
    return offset;
72
}
73
74
/// Copy private-state relocation records into native catalog storage.
75
unsafe fn relocations(input: *[shared::Relocation], output: &mut [u8], used: &mut u32) -> u32 throws (shared::Error) {
76
    if input.len > output.len / @sizeOf(shared::Relocation) { throw shared::Error::Capacity; }
77
    let size = input.len * @sizeOf(shared::Relocation);
78
    let offset = try reserve(output, used, size, @alignOf(shared::Relocation));
79
    try! mem::copy(&mut output[offset..offset + size], raw(input.ptr, size));
80
    return offset;
81
}
82
83
/// Pack native Entry records followed by all referenced metadata and source bytes.
84
/// Code is placed separately at each package's codeAddress. The target base must
85
/// have Entry alignment. Return the used extent. Failure leaves partial output.
86
export unsafe fn pack(entries: &[Entry], base: u64, output: &mut [u8]) -> u32 throws (shared::Error) {
87
    assert @sizeOf(*[u8]) == 16;
88
    if (base & (@alignOf(Entry) as u64 - 1)) <> 0 { throw shared::Error::Alignment; }
89
    if base > 0xffffffffffffffff - output.len as u64 { throw shared::Error::Range; }
90
    if entries.len > output.len / @sizeOf(Entry) { throw shared::Error::Capacity; }
91
    let mut used: u32 = 0;
92
    let start = try reserve(output, &mut used, entries.len * @sizeOf(Entry), @alignOf(Entry));
93
    for entry, i in entries {
94
        let at = i * @sizeOf(Entry);
95
        try! mem::copy(&mut output[at..at + @sizeOf(Entry)], raw(&entry, @sizeOf(Entry)));
96
        let source = try bytes(entry.source, output, &mut used);
97
        let name = try bytes(entry.package.name, output, &mut used);
98
        let required = try dependencies(entry.package.dependencies, base, output, &mut used);
99
        let exports = try symbols(entry.package.exports, base, output, &mut used);
100
        let template = try bytes(entry.package.template, output, &mut used);
101
        let fixups = try relocations(entry.package.relocations, output, &mut used);
102
        slice(output, at + field(&entry, &entry.source), base + source as u64, entry.source.len);
103
        slice(output, at + field(&entry, &entry.package.name), base + name as u64, entry.package.name.len);
104
        slice(output, at + field(&entry, &entry.package.dependencies), base + required as u64, entry.package.dependencies.len);
105
        slice(output, at + field(&entry, &entry.package.code), entry.package.codeAddress, entry.package.code.len);
106
        slice(output, at + field(&entry, &entry.package.exports), base + exports as u64, entry.package.exports.len);
107
        slice(output, at + field(&entry, &entry.package.template), base + template as u64, entry.package.template.len);
108
        slice(output, at + field(&entry, &entry.package.relocations), base + fixups as u64, entry.package.relocations.len);
109
    }
110
    return used;
111
}