compiler/
kernel/
lib/
examples/
std/
arch/
rv64/
asm/
image/
tests.rad
8.0 KiB
shared/
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/image/tests.rad
raw
| 1 | //! Native image placement, relocation, and wire-header checks. |
| 2 | |
| 3 | use std::testing; |
| 4 | use std::lang::il; |
| 5 | use std::lang::alloc; |
| 6 | use std::lang::gen::data; |
| 7 | use std::collections::dict; |
| 8 | use std::arch::rv64; |
| 9 | use std::arch::rv64::image; |
| 10 | use std::arch::rv64::emit; |
| 11 | use std::arch::rv64::encode; |
| 12 | |
| 13 | /// Arena for one emitter and its bounded relocation tables. |
| 14 | static MEMORY: [u8; 16777216] = [0; 16777216]; |
| 15 | /// Data symbol lookup workspace. |
| 16 | unsafe static ENTRIES: [dict::Entry; data::DATA_SYM_TABLE_SIZE] = undefined; |
| 17 | |
| 18 | /// Construct a small image with three disjoint high-address segments. |
| 19 | fn layout() -> image::Layout { |
| 20 | return image::Layout { |
| 21 | entry: 0x80000004, |
| 22 | code: image::Segment { address: 0x80000000, initialized: 8, memory: 8 }, |
| 23 | roData: image::Segment { address: 0x80001000, initialized: 3, memory: 16 }, |
| 24 | rwData: image::Segment { address: 0x80002000, initialized: 4, memory: 4096 }, |
| 25 | }; |
| 26 | } |
| 27 | |
| 28 | /// Check the exact 64-byte little-endian header. |
| 29 | @test fn header() throws (testing::TestError) { |
| 30 | let bytes = try image::header(layout()) catch { |
| 31 | throw testing::TestError::Failed; |
| 32 | }; |
| 33 | try testing::expectBytesEq(&bytes[..], &[ |
| 34 | 82, 65, 68, 48, 2, 0, 0, 0, 4, 0, 0, 128, 0, 0, 0, 0, |
| 35 | 0, 0, 0, 128, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, |
| 36 | 0, 16, 0, 128, 0, 0, 0, 0, 3, 0, 0, 0, 16, 0, 0, 0, |
| 37 | 0, 32, 0, 128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 16, 0, 0, |
| 38 | ]); |
| 39 | } |
| 40 | |
| 41 | /// Check a rejected image layout. |
| 42 | fn invalid(item: image::Layout, expected: image::Error) throws (testing::TestError) { |
| 43 | let mut failed = false; |
| 44 | try image::validate(item) catch err { |
| 45 | try testing::expect(err == expected); |
| 46 | set failed = true; |
| 47 | }; |
| 48 | try testing::expect(failed); |
| 49 | } |
| 50 | |
| 51 | /// Check overlap, alignment, size, entry, and address overflow failures. |
| 52 | @test fn validation() throws (testing::TestError) { |
| 53 | let mut item = layout(); |
| 54 | set item.rwData.address = item.roData.address + 8; |
| 55 | try invalid(item, image::Error::Overlap); |
| 56 | set item = layout(); |
| 57 | set item.roData.address = item.code.address; |
| 58 | try invalid(item, image::Error::Overlap); |
| 59 | set item = layout(); |
| 60 | set item.rwData.address += 1; |
| 61 | try invalid(item, image::Error::Alignment); |
| 62 | set item = layout(); |
| 63 | set item.entry += 1; |
| 64 | try invalid(item, image::Error::Alignment); |
| 65 | set item = layout(); |
| 66 | set item.entry = item.code.address + item.code.initialized as u64; |
| 67 | try invalid(item, image::Error::Entry); |
| 68 | set item = layout(); |
| 69 | set item.roData.initialized = 17; |
| 70 | try invalid(item, image::Error::Size); |
| 71 | set item = layout(); |
| 72 | set item.rwData.address = 0xfffffffffffffff8; |
| 73 | try invalid(item, image::Error::Overflow); |
| 74 | set item = layout(); |
| 75 | set item.roData.address = item.code.address + 8; |
| 76 | try image::validate(item) catch { |
| 77 | throw testing::TestError::Failed; |
| 78 | }; |
| 79 | } |
| 80 | |
| 81 | /// Check AUIPC/ADDI limits without overflowing unsigned address arithmetic. |
| 82 | @test fn displacements() throws (testing::TestError) { |
| 83 | try testing::expect(image::displacement(0x180000000, 0x180002000) == 8192); |
| 84 | try testing::expect(image::displacement(0x180002000, 0x180000000) == -8192); |
| 85 | try testing::expect(image::displacement(0, 0x7ffff7ff) == 0x7ffff7ff); |
| 86 | try testing::expect(image::displacement(0, 0x7ffff800) == nil); |
| 87 | try testing::expect(image::displacement(0x80000000, 0) == -2147483648); |
| 88 | try testing::expect(image::displacement(0x80000001, 0) == nil); |
| 89 | try testing::expect(image::displacement(0, 0xffffffffffffffff) == nil); |
| 90 | try testing::expect(image::displacement(0xffffffffffffffff, 0) == nil); |
| 91 | } |
| 92 | |
| 93 | /// Check high physical placement, zero-fill extents, and 64-bit data relocations. |
| 94 | @test unsafe fn nativeProgram() throws (testing::TestError) { |
| 95 | let mut arena = alloc::new(&mut MEMORY[..]); |
| 96 | let mut generator = try! rv64::beginProgram(rv64::ProgramOptions { |
| 97 | entryPatch: rv64::EntryPatch::None, debug: false, |
| 98 | placement: image::Placement::Physical { |
| 99 | code: 0x180000000, roData: 0x180001000, rwData: 0x180002000, entry: 0x180000000, |
| 100 | }, |
| 101 | }, &mut arena); |
| 102 | emit::recordFunc(&mut generator.e, "p::entry"); |
| 103 | emit::recordFuncOffset(&mut generator.e, "p::entry"); |
| 104 | emit::recordDataAddrLoad(&mut generator.e, "p::pointer", rv64::A0); |
| 105 | let globals = &[ |
| 106 | il::Data { |
| 107 | name: "p::pointer", size: 8, alignment: 8, readOnly: false, isZeroInit: false, |
| 108 | values: &[il::DataValue { item: il::DataItem::Fn("p::entry"), count: 1 }], |
| 109 | }, |
| 110 | il::Data { |
| 111 | name: "p::zero", size: 4096, alignment: 8, readOnly: false, isZeroInit: true, values: &[], |
| 112 | }, |
| 113 | ]; |
| 114 | unsafe static syms: [data::DataSym; 2] = undefined; |
| 115 | let mut ro: [u8; 8] = [0; 8]; |
| 116 | let mut rw: [u8; 8] = [0; 8]; |
| 117 | let result = try rv64::finishProgram(generator, globals, |
| 118 | rv64::Storage { dataSyms: &mut syms[..], dataSymEntries: &mut ENTRIES[..] }, |
| 119 | &[], &mut ro[..], &mut rw[..] |
| 120 | ) catch { |
| 121 | throw testing::TestError::Failed; |
| 122 | }; |
| 123 | try testing::expect(result.layout.code.address == 0x180000000); |
| 124 | try testing::expect(result.layout.rwData.initialized == 8); |
| 125 | try testing::expect(result.layout.rwData.memory == 4104); |
| 126 | try testing::expect(syms[1].addr == 0x180002008); |
| 127 | try testing::expectBytesEq(&rw[..], &[0, 0, 0, 128, 1, 0, 0, 0]); |
| 128 | try testing::expect(result.code[0] == encode::auipc(rv64::A0, 2)); |
| 129 | try testing::expect(result.code[1] == encode::addi(rv64::A0, rv64::A0, 0)); |
| 130 | } |
| 131 | |
| 132 | /// Check bounded data-layout failure without wrapped addresses or symbol writes. |
| 133 | @test unsafe fn dataLayout() throws (testing::TestError) { |
| 134 | let item = il::Data { |
| 135 | name: "p::data", size: 16, alignment: 8, readOnly: false, isZeroInit: true, values: &[], |
| 136 | }; |
| 137 | unsafe static syms: [data::DataSym; 1] = undefined; |
| 138 | let mut count: u32 = 0; |
| 139 | let mut failed = false; |
| 140 | try data::layoutSection(&[item], &mut syms[..], &mut count, 0xfffffffffffffff8, false) catch err { |
| 141 | try testing::expect(err == data::Error::Overflow); |
| 142 | set failed = true; |
| 143 | }; |
| 144 | try testing::expect(failed and count == 0); |
| 145 | set failed = false; |
| 146 | try data::layoutSection(&[item], &mut syms[..0], &mut count, 0x80000000, false) catch err { |
| 147 | try testing::expect(err == data::Error::Capacity); |
| 148 | set failed = true; |
| 149 | }; |
| 150 | try testing::expect(failed and count == 0); |
| 151 | set failed = false; |
| 152 | try data::layoutSectionAtOffset(&[item], &mut syms[..], &mut count, 0, 0xfffffff8, false) catch err { |
| 153 | try testing::expect(err == data::Error::Overflow); |
| 154 | set failed = true; |
| 155 | }; |
| 156 | try testing::expect(failed and count == 0); |
| 157 | } |
| 158 | |
| 159 | /// Keep declared symbol extents and alignment gaps in initialized data. |
| 160 | @test unsafe fn initializedExtents() throws (testing::TestError) { |
| 161 | let mut arena = alloc::new(&mut MEMORY[..]); |
| 162 | let mut generator = try! rv64::beginProgram(rv64::ProgramOptions { |
| 163 | entryPatch: rv64::EntryPatch::None, debug: false, |
| 164 | placement: image::Placement::Physical { |
| 165 | code: 0x80000000, roData: 0x80001000, rwData: 0x80002000, entry: 0x80000000, |
| 166 | }, |
| 167 | }, &mut arena); |
| 168 | emit::recordDataAddrLoad(&mut generator.e, "p::second", rv64::A0); |
| 169 | let globals = &[ |
| 170 | il::Data { |
| 171 | name: "p::first", size: 5, alignment: 1, readOnly: false, isZeroInit: false, |
| 172 | values: &[il::DataValue { item: il::DataItem::Str("a"), count: 1 }], |
| 173 | }, |
| 174 | il::Data { |
| 175 | name: "p::second", size: 8, alignment: 8, readOnly: false, isZeroInit: false, |
| 176 | values: &[il::DataValue { item: il::DataItem::Str("b"), count: 1 }], |
| 177 | }, |
| 178 | ]; |
| 179 | unsafe static syms: [data::DataSym; 2] = undefined; |
| 180 | let mut ro: [u8; 0] = []; |
| 181 | let mut rw: [u8; 16] = [255; 16]; |
| 182 | let result = try rv64::finishProgram(generator, globals, |
| 183 | rv64::Storage { dataSyms: &mut syms[..], dataSymEntries: &mut ENTRIES[..] }, |
| 184 | &[], &mut ro[..], &mut rw[..] |
| 185 | ) catch { |
| 186 | throw testing::TestError::Failed; |
| 187 | }; |
| 188 | try testing::expect(result.layout.rwData.initialized == 16); |
| 189 | try testing::expect(syms[1].addr == 0x80002008); |
| 190 | try testing::expectBytesEq(&rw[..], &[97, 0, 0, 0, 0, 0, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0]); |
| 191 | } |