1mod aarch64_ldst_imm64;
7
8pub mod assembler;
9pub mod encoder;
10pub mod error;
11pub mod object;
12pub mod parser;
13pub mod runtime;
14pub mod target;
15
16pub use assembler::RasAssembler;
17pub use error::RasError;
18pub use object::ObjectWriteOptions;
19pub use runtime::{ExecutableMemory, RasRuntime};
20pub use target::{
21 is_assembly_target_supported, is_jit_arch_supported, is_object_file_supported,
22 supported_jit_targets_hint,
23};
24
25use lamina_platform::{TargetArchitecture, TargetOperatingSystem};
26
27pub struct Ras {
29 assembler: RasAssembler,
30}
31
32impl Ras {
33 pub fn new(
34 target_arch: TargetArchitecture,
35 target_os: TargetOperatingSystem,
36 ) -> Result<Self, RasError> {
37 Self::with_object_write_options(target_arch, target_os, ObjectWriteOptions::default())
38 }
39
40 pub fn with_object_write_options(
41 target_arch: TargetArchitecture,
42 target_os: TargetOperatingSystem,
43 object_write_options: ObjectWriteOptions,
44 ) -> Result<Self, RasError> {
45 Ok(Self {
46 assembler: RasAssembler::with_object_write_options(
47 target_arch,
48 target_os,
49 object_write_options,
50 )?,
51 })
52 }
53
54 pub fn assemble(
55 &mut self,
56 asm_text: &str,
57 output_path: &std::path::Path,
58 ) -> Result<(), RasError> {
59 self.assembler
60 .assemble_text_to_object(asm_text, output_path)
61 }
62
63 pub fn assemble_file(
64 &mut self,
65 input_path: &std::path::Path,
66 output_path: &std::path::Path,
67 ) -> Result<(), RasError> {
68 let asm_text = std::fs::read_to_string(input_path)
69 .map_err(|e| RasError::IoError(format!("Failed to read input: {}", e)))?;
70 self.assemble(&asm_text, output_path)
71 }
72
73 #[cfg(feature = "encoder")]
74 pub fn compile_mir_to_binary(
75 &mut self,
76 module: &lamina_mir::Module,
77 ) -> Result<Vec<u8>, RasError> {
78 self.assembler.compile_mir_to_binary(module)
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn test_assemble_gas_style_to_elf() {
88 let asm = r#"
89.text
90.globl main
91main:
92 movq $42, %rax
93 ret
94"#;
95 let mut ras =
96 Ras::new(TargetArchitecture::X86_64, TargetOperatingSystem::Linux).expect("ras new");
97 let path = std::env::temp_dir().join("ras_gas_style_test.o");
98 ras.assemble(asm, &path).expect("assemble");
99 let buf = std::fs::read(&path).expect("read");
100 let _ = std::fs::remove_file(&path);
101 assert!(buf.len() >= 64);
102 assert_eq!(&buf[0..4], &[0x7f, b'E', b'L', b'F']);
103 }
104
105 #[test]
106 fn test_assemble_memory_operands() {
107 let asm = r#"
108.text
109.globl main
110main:
111 pushq %rbp
112 movq %rsp, %rbp
113 subq $16, %rsp
114 movq $42, %rax
115 movq %rax, -8(%rbp)
116 movq -8(%rbp), %rax
117 addq $16, %rsp
118 popq %rbp
119 ret
120"#;
121 let mut ras =
122 Ras::new(TargetArchitecture::X86_64, TargetOperatingSystem::Linux).expect("ras new");
123 let path = std::env::temp_dir().join("ras_mem_test.o");
124 ras.assemble(asm, &path).expect("assemble");
125 let buf = std::fs::read(&path).expect("read");
126 let _ = std::fs::remove_file(&path);
127 assert!(buf.len() >= 64);
128 assert_eq!(&buf[0..4], &[0x7f, b'E', b'L', b'F']);
129 }
130
131 #[test]
132 fn test_assemble_jmp_label_resolution() {
133 let asm = r#"
134.text
135.globl main
136main:
137 pushq %rbp
138 movq %rsp, %rbp
139 subq $16, %rsp
140 movq $0, %rax
141 jmp .L_exit
142.L_exit:
143 addq $16, %rsp
144 popq %rbp
145 ret
146"#;
147 let mut ras =
148 Ras::new(TargetArchitecture::X86_64, TargetOperatingSystem::Linux).expect("ras new");
149 let path = std::env::temp_dir().join("ras_jmp_test.o");
150 ras.assemble(asm, &path).expect("assemble");
151 let buf = std::fs::read(&path).expect("read");
152 let _ = std::fs::remove_file(&path);
153 assert!(buf.len() >= 64);
154 assert_eq!(&buf[0..4], &[0x7f, b'E', b'L', b'F']);
155 }
156
157 #[test]
158 fn test_assemble_rip_relative_lea_label() {
159 let asm = r#"
162.section .rodata
163.L_fmt: .asciz "%lld\n"
164.text
165.globl get_fmt
166get_fmt:
167 leaq .L_fmt(%rip), %rax
168 ret
169"#;
170 let mut ras =
171 Ras::new(TargetArchitecture::X86_64, TargetOperatingSystem::Linux).expect("ras new");
172 let path = std::env::temp_dir().join("ras_rip_rel_test.o");
173 ras.assemble(asm, &path).expect("assemble should succeed");
174 let buf = std::fs::read(&path).expect("read");
175 let _ = std::fs::remove_file(&path);
176 assert_eq!(&buf[0..4], &[0x7f, b'E', b'L', b'F']);
178 }
179
180 #[test]
181 fn test_assemble_arx64_label_resolution_to_elf() {
182 let asm = r#"
183.text
184.globl main
185main:
186 addi r5, r0, 1
187 j done
188 addi r5, r0, 2
189done:
190 ret
191"#;
192 let mut ras =
193 Ras::new(TargetArchitecture::Arx64, TargetOperatingSystem::Linux).expect("ras new");
194 let path = std::env::temp_dir().join("ras_arx64_label_test.o");
195 ras.assemble(asm, &path).expect("assemble");
196 let buf = std::fs::read(&path).expect("read");
197 let _ = std::fs::remove_file(&path);
198 assert!(buf.len() >= 64);
199 assert_eq!(&buf[0..4], &[0x7f, b'E', b'L', b'F']);
200 }
201}