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