compiler: Finalize RV64 programs in checked code
edab4b3c9423bf31522e6219030d82ae25057548b9733bb8f55f5fa79079518f
1 parent
25a7fab8
lib/std/arch/rv64.rad
+12 -0
| 367 | 367 | globalData: &[il::Data], |
|
| 368 | 368 | storage: Storage, |
|
| 369 | 369 | roDataPrefix: *[u8], |
|
| 370 | 370 | roDataBuf: &mut [u8], |
|
| 371 | 371 | rwDataBuf: &mut [u8] |
|
| 372 | + | ) -> Program throws (Error) { |
|
| 373 | + | return try linkProgram(input, globalData, storage, roDataPrefix, roDataBuf, rwDataBuf); |
|
| 374 | + | } |
|
| 375 | + | ||
| 376 | + | /// Lay out data, resolve relocations, and publish the completed program. |
|
| 377 | + | fn linkProgram( |
|
| 378 | + | input: Generator, |
|
| 379 | + | globalData: &[il::Data], |
|
| 380 | + | storage: Storage, |
|
| 381 | + | roDataPrefix: *[u8], |
|
| 382 | + | roDataBuf: &mut [u8], |
|
| 383 | + | rwDataBuf: &mut [u8] |
|
| 372 | 384 | ) -> Program throws (Error) { |
|
| 373 | 385 | let mut generator = input; |
|
| 374 | 386 | try emit::check(&generator.e); |
|
| 375 | 387 | let mut roBase: u64 = RO_DATA_BASE as u64; |
|
| 376 | 388 | let mut rwBase: u64 = RW_DATA_BASE as u64; |
lib/std/arch/rv64/image/tests.rad
+39 -0
| 46 | 46 | set failed = true; |
|
| 47 | 47 | }; |
|
| 48 | 48 | try testing::expect(failed); |
|
| 49 | 49 | } |
|
| 50 | 50 | ||
| 51 | + | /// Finalization preserves hosted placement and propagates bounded failures. |
|
| 52 | + | @test unsafe fn programFinalization() throws (testing::TestError) { |
|
| 53 | + | for scenario in 0..6 { |
|
| 54 | + | let mut arena = alloc::new(&mut MEMORY[..]); |
|
| 55 | + | let placement = image::Placement::Physical { |
|
| 56 | + | code: 0x80000000, roData: 0x80000000, rwData: 0x80002000, entry: 0x80000000, |
|
| 57 | + | } if scenario == 5 else image::Placement::Hosted; |
|
| 58 | + | let entryPatch = rv64::EntryPatch::Reserved(nil) if scenario == 2 else rv64::EntryPatch::None; |
|
| 59 | + | let mut generator = try! rv64::beginProgram(rv64::ProgramOptions { |
|
| 60 | + | entryPatch, debug: false, placement, |
|
| 61 | + | }, &mut arena); |
|
| 62 | + | emit::emit(&mut generator.e, encode::nop()); |
|
| 63 | + | if scenario == 3 { set generator.e.error = rv64::Error::Capacity; } |
|
| 64 | + | if scenario == 4 { emit::recordCall(&mut generator.e, "missing"); } |
|
| 65 | + | let mut ro: [u8; 5] = [42; 5]; |
|
| 66 | + | let mut rw: [u8; 0] = []; |
|
| 67 | + | let capacity: u32 = 2 if scenario == 1 else 3; |
|
| 68 | + | let result = try rv64::finishProgram(generator, &[], |
|
| 69 | + | rv64::Storage { dataSyms: &mut [], dataSymEntries: &mut ENTRIES[..] }, |
|
| 70 | + | &[7, 8, 9], &mut ro[1..capacity + 1], &mut rw[..] |
|
| 71 | + | ) catch err { |
|
| 72 | + | // Record the failure before the next independent generator is built. |
|
| 73 | + | let expected = rv64::Error::Image(image::Error::Overlap) if scenario == 5 |
|
| 74 | + | else rv64::Error::Symbol if scenario == 2 or scenario == 4 |
|
| 75 | + | else rv64::Error::Capacity; |
|
| 76 | + | assert err == expected; |
|
| 77 | + | assert scenario <> 0; |
|
| 78 | + | assert ro[0] == 42 and ro[capacity + 1] == 42; |
|
| 79 | + | continue; |
|
| 80 | + | }; |
|
| 81 | + | assert scenario == 0; |
|
| 82 | + | assert result.layout.code.address == rv64::RO_DATA_BASE as u64 + 8; |
|
| 83 | + | assert result.code.len == 1 and result.code[0] == encode::nop(); |
|
| 84 | + | assert result.roDataSize == 3 and result.rwDataSize == 0; |
|
| 85 | + | assert ro[0] == 42 and ro[4] == 42; |
|
| 86 | + | assert ro[1] == 7 and ro[2] == 8 and ro[3] == 9; |
|
| 87 | + | } |
|
| 88 | + | } |
|
| 89 | + | ||
| 51 | 90 | /// Construct a small image with three disjoint high-address segments. |
|
| 52 | 91 | fn layout() -> image::Layout { |
|
| 53 | 92 | return image::Layout { |
|
| 54 | 93 | entry: 0x80000004, |
|
| 55 | 94 | code: image::Segment { address: 0x80000000, initialized: 8, memory: 8 }, |