compiler: Emit and patch assembly through safe helpers
eee99ebe5262843d2fbf5f0ee4349f50cefecafa0cf57fb3004383607e83dd67
1 parent
e4ef0fa5
lib/std/arch/rv64/asm/emit.rad
+12 -12
| 6 | 6 | ||
| 7 | 7 | use std::collections::dict; |
|
| 8 | 8 | use std::lang::gen; |
|
| 9 | 9 | ||
| 10 | 10 | /// Define a symbol at the current text or data offset. |
|
| 11 | - | export unsafe fn defineSymbol(a: &mut super::Assembler, name: *[u8]) { |
|
| 11 | + | export fn defineSymbol(a: &mut super::Assembler, name: *[u8]) { |
|
| 12 | 12 | let idx = a.symbolsLen; |
|
| 13 | 13 | let offset: i32 = a.dataLen as i32 |
|
| 14 | 14 | if a.section == super::Section::Data |
|
| 15 | 15 | else a.textLen as i32 * rv64::INSTR_SIZE; |
|
| 16 | 16 |
| 24 | 24 | set a.symbolsLen += 1; |
|
| 25 | 25 | dict::insert(&mut a.symbolMap, name, idx as i32); |
|
| 26 | 26 | } |
|
| 27 | 27 | ||
| 28 | 28 | /// Append one encoded instruction word to the text section. |
|
| 29 | - | export unsafe fn emitText(a: &mut super::Assembler, word: u32) throws (super::Error) { |
|
| 29 | + | export fn emitText(a: &mut super::Assembler, word: u32) throws (super::Error) { |
|
| 30 | 30 | if a.textLen >= a.text.len { |
|
| 31 | 31 | throw super::Error::TextOverflow; |
|
| 32 | 32 | } |
|
| 33 | 33 | set a.text[a.textLen] = word; |
|
| 34 | 34 | set a.textLen += 1; |
|
| 35 | 35 | } |
|
| 36 | 36 | ||
| 37 | 37 | /// Append `words` no-op instructions to the text section. |
|
| 38 | - | export unsafe fn emitTextPadding(a: &mut super::Assembler, words: u32) throws (super::Error) { |
|
| 38 | + | export fn emitTextPadding(a: &mut super::Assembler, words: u32) throws (super::Error) { |
|
| 39 | 39 | for _ in 0..words { |
|
| 40 | 40 | try emitText(a, encode::nop()); |
|
| 41 | 41 | } |
|
| 42 | 42 | } |
|
| 43 | 43 | ||
| 44 | 44 | /// Append one byte to the data section. |
|
| 45 | - | export unsafe fn emitByte(a: &mut super::Assembler, byte: u8) throws (super::Error) { |
|
| 45 | + | export fn emitByte(a: &mut super::Assembler, byte: u8) throws (super::Error) { |
|
| 46 | 46 | if a.dataLen >= a.data.len { |
|
| 47 | 47 | throw super::Error::DataOverflow; |
|
| 48 | 48 | } |
|
| 49 | 49 | set a.data[a.dataLen] = byte; |
|
| 50 | 50 | set a.dataLen += 1; |
|
| 51 | 51 | } |
|
| 52 | 52 | ||
| 53 | 53 | /// Emit a little-endian integer with `bytes` bytes. |
|
| 54 | - | unsafe fn emitDataInt(a: &mut super::Assembler, bits: u64, bytes: u32) throws (super::Error) { |
|
| 54 | + | fn emitDataInt(a: &mut super::Assembler, bits: u64, bytes: u32) throws (super::Error) { |
|
| 55 | 55 | for i in 0..bytes { |
|
| 56 | 56 | try emitByte(a, ((bits >> ((i as u64) * super::BITS_PER_BYTE)) & super::BYTE_MASK) as u8); |
|
| 57 | 57 | } |
|
| 58 | 58 | } |
|
| 59 | 59 |
| 63 | 63 | set a.data[offset + i] = ((bits >> ((i as u64) * super::BITS_PER_BYTE)) & super::BYTE_MASK) as u8; |
|
| 64 | 64 | } |
|
| 65 | 65 | } |
|
| 66 | 66 | ||
| 67 | 67 | /// Emit an integer data directive value. |
|
| 68 | - | export unsafe fn emitDataValue(a: &mut super::Assembler, value: i64, width: super::DataWidth) throws (super::Error) { |
|
| 68 | + | export fn emitDataValue(a: &mut super::Assembler, value: i64, width: super::DataWidth) throws (super::Error) { |
|
| 69 | 69 | match width { |
|
| 70 | 70 | case super::DataWidth::Word => try emitDataInt(a, value as u64, rv64::WORD_SIZE as u32), |
|
| 71 | 71 | case super::DataWidth::Dword => try emitDataInt(a, value as u64, rv64::DWORD_SIZE as u32), |
|
| 72 | 72 | } |
|
| 73 | 73 | } |
|
| 74 | 74 | ||
| 75 | 75 | /// Record a data-section symbol fixup and reserve its bytes. |
|
| 76 | - | export unsafe fn recordDataFixup(a: &mut super::Assembler, target: *[u8], width: super::DataWidth) throws (super::Error) { |
|
| 76 | + | export fn recordDataFixup(a: &mut super::Assembler, target: *[u8], width: super::DataWidth) throws (super::Error) { |
|
| 77 | 77 | let offset = a.dataLen; |
|
| 78 | 78 | match width { |
|
| 79 | 79 | case super::DataWidth::Word => { |
|
| 80 | 80 | recordFixup(a, target, super::FixupInfo::Word { offset }); |
|
| 81 | 81 | try emitDataInt(a, 0, rv64::WORD_SIZE as u32); |
| 86 | 86 | } |
|
| 87 | 87 | } |
|
| 88 | 88 | } |
|
| 89 | 89 | ||
| 90 | 90 | /// Record a pending symbol fixup. |
|
| 91 | - | unsafe fn recordFixup(a: &mut super::Assembler, symbol: *[u8], info: super::FixupInfo) { |
|
| 91 | + | fn recordFixup(a: &mut super::Assembler, symbol: *[u8], info: super::FixupInfo) { |
|
| 92 | 92 | assert a.fixupsLen < a.fixups.len, "recordFixup: fixup buffer full"; |
|
| 93 | 93 | set a.fixups[a.fixupsLen] = super::Fixup { symbol, info }; |
|
| 94 | 94 | set a.fixupsLen += 1; |
|
| 95 | 95 | } |
|
| 96 | 96 | ||
| 97 | 97 | /// Record a text fixup that must be resolved after all program text is known. |
|
| 98 | - | unsafe fn recordExternalFixup(a: &mut super::Assembler, fixup: super::Fixup) { |
|
| 98 | + | fn recordExternalFixup(a: &mut super::Assembler, fixup: super::Fixup) { |
|
| 99 | 99 | assert a.externalFixupsLen < a.externalFixups.len, "recordExternalFixup: fixup buffer full"; |
|
| 100 | 100 | set a.externalFixups[a.externalFixupsLen] = fixup; |
|
| 101 | 101 | set a.externalFixupsLen += 1; |
|
| 102 | 102 | } |
|
| 103 | 103 | ||
| 104 | 104 | /// Record a text-section symbol fixup and reserve its instruction words. |
|
| 105 | - | export unsafe fn recordTextFixup(a: &mut super::Assembler, symbol: *[u8], info: super::FixupInfo, words: u32) throws (super::Error) { |
|
| 105 | + | export fn recordTextFixup(a: &mut super::Assembler, symbol: *[u8], info: super::FixupInfo, words: u32) throws (super::Error) { |
|
| 106 | 106 | recordFixup(a, symbol, info); |
|
| 107 | 107 | try emitTextPadding(a, words); |
|
| 108 | 108 | } |
|
| 109 | 109 | ||
| 110 | 110 | /// Find a previously defined symbol by name. |
| 121 | 121 | } |
|
| 122 | 122 | return symbol.offset + (a.dataBase as i32); |
|
| 123 | 123 | } |
|
| 124 | 124 | ||
| 125 | 125 | /// Resolve final symbol references and patch all delayed output. |
|
| 126 | - | export unsafe fn finishProgram(a: &mut super::Assembler) throws (super::Error) { |
|
| 126 | + | export fn finishProgram(a: &mut super::Assembler) throws (super::Error) { |
|
| 127 | 127 | for i in 0..a.fixupsLen { |
|
| 128 | 128 | let fixup = a.fixups[i]; |
|
| 129 | 129 | let symbol = findSymbol(a, fixup.symbol) else { |
|
| 130 | 130 | match fixup.info { |
|
| 131 | 131 | case super::FixupInfo::Jal { .. }, super::FixupInfo::Addr { .. } => { |
| 198 | 198 | case super::BranchOp::Bgt => return encode::bgt(rs1, rs2, imm), |
|
| 199 | 199 | } |
|
| 200 | 200 | } |
|
| 201 | 201 | ||
| 202 | 202 | /// Decode string literal escapes and emit the resulting data bytes. |
|
| 203 | - | export unsafe fn emitDecodedString(a: &mut super::Assembler, literal: *[u8]) throws (super::Error) { |
|
| 203 | + | export fn emitDecodedString(a: &mut super::Assembler, literal: *[u8]) throws (super::Error) { |
|
| 204 | 204 | let raw = &literal[super::QUOTE_DELIM_LEN..literal.len - super::QUOTE_DELIM_LEN]; |
|
| 205 | 205 | let mut i: u32 = 0; |
|
| 206 | 206 | ||
| 207 | 207 | while i < raw.len { |
|
| 208 | 208 | if raw[i] == '\\' and i + 1 < raw.len { |
lib/std/arch/rv64/asm/parser.rad
+2 -2
| 106 | 106 | } |
|
| 107 | 107 | return value as i32; |
|
| 108 | 108 | } |
|
| 109 | 109 | ||
| 110 | 110 | /// Define a label at the current text or data offset. |
|
| 111 | - | unsafe fn defineSymbol(a: &mut super::Assembler, name: *[u8], tok: scanner::Token) throws (super::Error) { |
|
| 111 | + | fn defineSymbol(a: &mut super::Assembler, name: *[u8], tok: scanner::Token) throws (super::Error) { |
|
| 112 | 112 | if dict::get(&a.symbolMap, name) <> nil { |
|
| 113 | 113 | throw failOnToken(tok, "duplicate label"); |
|
| 114 | 114 | } |
|
| 115 | 115 | emit::defineSymbol(a, name); |
|
| 116 | 116 | } |
|
| 117 | 117 | ||
| 118 | 118 | /// Emit a parsed integer data value after applying source-level range checks. |
|
| 119 | - | unsafe fn emitDataValue(a: &mut super::Assembler, value: i64, width: super::DataWidth) throws (super::Error) { |
|
| 119 | + | fn emitDataValue(a: &mut super::Assembler, value: i64, width: super::DataWidth) throws (super::Error) { |
|
| 120 | 120 | match width { |
|
| 121 | 121 | case super::DataWidth::Word => |
|
| 122 | 122 | try emit::emitDataValue(a, (try expectI32Value(a, value, "word literal out of range")) as i64, width), |
|
| 123 | 123 | case super::DataWidth::Dword => |
|
| 124 | 124 | try emit::emitDataValue(a, value, width), |