compiler: Write RV64 images through checked byte slices

cb284e737d750af0b52f5fc609cbb25d151286bdc69870b237d800d1373b3e7b
Alexis Sellier committed ago 1 parent f28b0751
compiler/radiance.rad +21 -10
38 38
/// Maximum number of test functions we can discover.
39 39
constant MAX_TESTS: u32 = 1024;
40 40
/// Maximum number of assembly source paths we can load per package.
41 41
constant MAX_ASM_MODULES: u32 = 64;
42 42
43 +
/// Byte size of the five u32 fields in a single-file RV64 image header.
44 +
constant IMAGE_HEADER_SIZE: u32 = @sizeOf([u32; 5]);
45 +
43 46
/// AST arena size (64 MB) - retains parsed nodes throughout compilation.
44 47
constant TEMP_ARENA_SIZE: u32 = 67108864;
45 48
/// Per-function lowering and register-allocation arena size (16 MB).
46 49
constant FN_ARENA_SIZE: u32 = 16777216;
47 50
/// Main arena size (176 MB) - lives throughout compilation.
830 833
        ast::Block { statements: stmts, isUnsafe: block.isUnsafe }
831 834
    ));
832 835
}
833 836
834 837
/// Write a self-contained RV64 image containing text and data sections.
835 -
unsafe fn writeImage(
836 -
    code: *[u32],
837 -
    roData: *[u8],
838 -
    rwData: *[u8],
838 +
fn writeImage(
839 +
    code: &[u8],
840 +
    roData: &[u8],
841 +
    rwData: &[u8],
839 842
    path: *[u8]
840 843
) -> bool {
841 -
    let mut header = rv64::imageHeader(code.len * rv64::INSTR_SIZE as u32, roData.len, rwData.len);
842 -
    let headerBytes: *unsafe [u8] = @sliceOf(&header[0] as *unsafe u8, header.len * rv64::WORD_SIZE as u32);
843 -
    let codeBytes = @sliceOf(code.ptr as *u8, code.len * rv64::INSTR_SIZE as u32);
844 +
    let header = rv64::imageHeader(code.len, roData.len, rwData.len);
845 +
    let mut headerBytes = [0 as u8; IMAGE_HEADER_SIZE];
846 +
    assert headerBytes.len == header.len * @sizeOf(u32);
847 +
    for word, index in header {
848 +
        for byte in 0..@sizeOf(u32) {
849 +
            set headerBytes[index * @sizeOf(u32) + byte] = (word >> (byte * 8)) as u8;
850 +
        }
851 +
    }
844 852
845 853
    let fd = unix::openOpts(path, unix::OpenFlags(*unix::O_WRONLY | *unix::O_CREAT | *unix::O_TRUNC), 420);
846 -
    if fd < 0 { return false; }
847 -
    let written = unix::writeAll(fd, headerBytes) and unix::writeAll(fd, codeBytes)
854 +
    if fd < 0 {
855 +
        return false;
856 +
    }
857 +
    let written = unix::writeAll(fd, &headerBytes[..]) and unix::writeAll(fd, code)
848 858
        and unix::writeAll(fd, roData) and unix::writeAll(fd, rwData);
849 859
    let closed = unix::close(fd) == 0;
850 860
    return written and closed;
851 861
}
852 862
1349 1359
        entryMode: CodegenEntryMode::None
1350 1360
            if startupPath <> nil
1351 1361
            else CodegenEntryMode::DefaultEntry,
1352 1362
    });
1353 1363
1364 +
    let codeBytes = @sliceOf(result.code.ptr as *u8, result.code.len * rv64::INSTR_SIZE as u32);
1354 1365
    if not writeImage(
1355 -
        result.code,
1366 +
        codeBytes,
1356 1367
        &RO_DATA_BUF[..result.roDataSize],
1357 1368
        &RW_DATA_BUF[..result.rwDataSize],
1358 1369
        outPath
1359 1370
    ) {
1360 1371
        throw error(&["fatal:", "failed to write output file"]);