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