compiler: Finalize RV64 programs in checked code

edab4b3c9423bf31522e6219030d82ae25057548b9733bb8f55f5fa79079518f
Alexis Sellier committed ago 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 },