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 {
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
}