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