compiler/
kernel/
lib/
examples/
std/
arch/
rv64/
asm/
image/
shared/
catalog.rad
6.1 KiB
tests.rad
10.8 KiB
asm.rad
24.5 KiB
atomicTests.rad
5.0 KiB
atomics.rad
3.6 KiB
bounds.rad
8.7 KiB
decode.rad
15.2 KiB
emit.rad
33.2 KiB
encode.rad
22.0 KiB
image.rad
4.5 KiB
isel.rad
51.0 KiB
printer.rad
14.2 KiB
shared.rad
16.8 KiB
tests.rad
17.2 KiB
rv64.rad
17.1 KiB
char/
collections/
lang/
sys/
arch.rad
68 B
char.rad
855 B
collections.rad
39 B
fmt.rad
8.3 KiB
intrinsics.rad
467 B
io.rad
1.7 KiB
lang.rad
276 B
mem.rad
2.3 KiB
sys.rad
179 B
testing.rad
2.4 KiB
tests.rad
15.7 KiB
vec.rad
3.2 KiB
std.rad
281 B
scripts/
seed/
sublime/
test/
vim/
.gitignore
336 B
.gitsigners
112 B
CONTRIBUTING
2.1 KiB
LICENSE
1.1 KiB
Makefile
9.2 KiB
README
2.5 KiB
STYLE
2.5 KiB
std.lib
1.5 KiB
std.lib.test
662 B
lib/std/arch/rv64/shared/catalog.rad
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 | } |