The Scalable Assembler System (SAS) is an assembler designed in Rust. Its key feature is the use of uniformly designed data structures to accelerate the assembly process and simplify adaptation. Compared to existing assemblers, SAS features a cleaner, more efficient architectural design and can reduce assembly time in certain scenarios.
SAS is currently still in active development. We welcome anyone to participate in its development or offer valuable suggestions.
Currently Supported ISAs: AMD64, AArch64, RISC-V. For specific adaptation details and ELF file format support status, please refer to the "Support Status" section.
- Highly Abstracted Modular Design: Uses standardized data structures to store data required for the assembly process, providing a universal abstraction of the assembly workflow. This greatly reduces the difficulty of maintaining and extending a multi-ISA assembler.
- Powered by Rust: Leverages Rust's memory safety features and zero-cost abstractions, combined with powerful compile-time optimizations from LLVM, to squeeze every drop of hardware performance.
- Significant Compilation Acceleration: Compared to the existing GNU Assembler (GAS), SAS can deliver a 30% to 100% performance boost (depending on the target ISA).
Please make sure you have configured the Rust compilation environment and cargo, and have a stable Internet connection. Download SAS to your local computer, and then run cargo build --release in the SAS directory.
The generated sas binary file will be saved in the ./target/release/ directory. You can move it to any location and run it. The way to use SAS is similar to other assemblers. The currently supported parameters are as follows:
-o|--output Accepts several strings. Changes the output object file address. Defaults to "test.uap".
-l|--log Takes a string that specifies the log file location. Special locations include "stdout" for standard output and "muted" to disable logging.
-e|--level Accepts an i32 decimal number. Specifies the log level. The lower the level, the more detailed the logs printed. The default is 0.
-f|--format Takes a string. Specifies the output file format. Currently supported formats are "scalable_executable" and "executable_and_linkable". Defaults to "scalable_executable".
--amd64 Accepts several strings. Specifies the address of AMD64 assembly or object files. Defaults to empty, which means no AMD64 assembly or linking.
--arm64 Accepts several strings. Specifies the address of AArch64 assembly or object file. Defaults to empty, which means no AArch64 assembly or linking.
--riscv64 Accepts several strings. Specifies the address of the RISCV64 assembly or object file. Defaults to empty, which means no RISCV64 assembly or linking.
-h|--help No arguments (for now). Print help information.
-L|--link No parameters. Use this parameter to use the SAS built-in linker. Currently this parameter is invalid. You need to modify config.link in main.rs and recompile to implement this function.
For example, using sas --amd64 blocksort.s bzip2.s bzlib.s compress.s crctable.s decompress.s huffman.s randtable.s -o bzip2.uap will read blocksort.s bzip2.s bzlib.s compress.s crctable.s decompress.s huffman.s randtable.s and assemble, then link, finally generate file test.uap 。
SAS will support more parameters in the future.
Thanks to SAS's unified data structure design, adding adaptations is quite simple. You only need to add the following to src/asmanager/${YOUR_ISA}/, and SAS will support your ISA:
- (Required) ISA register information stored as the
Registertype. Recommended forsrc/asmanager/${YOUR_ISA}/arch.rs. - (Required) ISA instruction information stored as
OperationDesc. Recommended forsrc/asmanager/${YOUR_ISA}/arch.rs. - (Required) An ISA object class implementing the
ArchDescinterface and its constructor. The constructor must initialize the SAS lexer and parser, and include necessary syntax processing functions. Recommended forsrc/asmanager/${YOUR_ISA}/mod.rs. - (Required) Machine instruction classes implementing the
OpCodeinterface. Recommended forsrc/asmanager/${YOUR_ISA}/mod.rs. - (Required) Implement any macro instructions exclusive to the ISA. Recommended for
src/asmanager/${YOUR_ISA}/mod.rs. - (Required) Add the ISA ID in
src/asmanager.rsand append the initialization function toARCH_VEC. The ISA ID corresponds to its position inARCH_VEC, so conflicts must be avoided. - (Recommended) Implement necessary unit tests.
- (Recommended) Write documentation, stored in
src/asmanager/${YOUR_ISA}/info.md. - (Recommended) Consolidate necessary constants in
src/asmanager/${YOUR_ISA}/data.rs. - (Recommended) Leave helpful suggestions for other SAS maintainers.
Next, let's introduce some of SAS's core data structures:
The Register class describes a register, including its name, number, and other information. The specific implementation is as follows.
pub struct Register{
pub name:&'static str,//register name
pub resource:u32,//reserved for future use
pub id:u16,//Stores the register number, and this field will be filled into the instruction during assembly.
pub class:u8,//Stores the register category number, which is defined by the ISA
pub flag:u8,
}
The Operand class describes an operand, which provides up to two register addressing and an immediate or label addressing, and provides custom flags for ISA use. It is defined as follows:
pub enum MemoryOffset {
None, // No additional addressing
Label(Box<str>), // Identifier-related addressing
Value(i64), // Constant-related addressing
// Float(f64), // Unused
}
pub struct Operand {
pub base: Option<&'static Register>, // Base address for memory addressing, or target register for register addressing
pub scale: Option<&'static Register>, // Scale register for indexed addressing
pub offset: MemoryOffset, // Holds other addressing mode data (defined above)
pub flag: u32,
pub class: u16, // Operand class. 0-127: memory-related (e.g., base addressing), 128-255: register addressing, 256: immediate addressing. The register addressing ID is universally defined as `register class ID | 128`. Further definitions are up to the ISA.
}
OperationDesc类依赖于Qualifier、OperandType类,具体实现如下:
pub enum OperandType {
// [Signed | Negative | | u64 | u32 | u16 | u8 | ? | 1 | 0]
// [15.. 4 | 3 | 2 | 1 | 0]
Immediate([u8; 2]), // Accepted immediate value info
Register(u64), // Accepted register class bitmask
Memory(u64), // Accepted memory addressing bitmask
Default(&'static Operand), // Default operand
Force(&'static Register), // Forced/mandatory operand
Judger(fn(opr: &[Operand], id: usize) -> bool), // Custom judger function (implement if necessary)
Same(usize), // Requires matching a specific element in the operand list
}
pub struct Qualifier {
pub target: &'static [OperandType], // Target operand type description required by this instruction variant
pub modifier: u64, // Modification operation description required by this variant, defined by ISA
}
pub struct OperationDesc {
pub name: &'static str, // Instruction name
pub operands: &'static [u16], // Description of how operands are filled into the instruction template
pub qualifiers: &'static [Qualifier], // All instruction variants for the template
pub operation: u64, // Instruction template base. (For VLIW, use an array for secondary referencing)
pub support: &'static [u64], // Supported target systems description. Defined by ISA
pub flag: u64, // Template flag bit. A value of -1 (u64::Max) means this is a macro instruction needing further processing.
}
The ArchDesc class provides encapsulation for the ISA. Documentation for this is to be added.
SyntaxManager might be refactored in the future. However, since the instruction matching and encoding processes are completely agnostic to the syntax handling process, this shouldn't cause major issues.
Instruction to complete.
Due to time and testing equipment limitations, we have only conducted limited testing on the devices and cannot guarantee that SAS generates correct instructions. We welcome anyone to participate in testing SAS and provide feedback.
Suggestions for improvements are especially appreciated.
SAS has ported some test scripts from LLVM-MC. You can run them using cargo test.
AMD64: Does not support X87, MMX, or 3DNow!. AVX512 is not yet supported but is planned for future updates. Other instructions need further testing to determine usability.
AArch64: Does not support SVE/SME, but support is planned for future updates. Other instructions need further testing to determine usability.
RISC-V64: Needs further testing to determine usability.
LoongArch: Not yet adapted, but adaptation is planned for the next phase.
ELF: Limited support for amd64,aarch64 and riscv64.
This project is licensed under the GNU GPLv3. We would be honored if this project could be accepted by GNU.
Sometimes, Rust is referenced as Genshin Impact in programming language.
You're right, But Rust is a compilation-time fighting game proudly presented by Mozilla.
In the world of Cargo -- where the referenced pointer will be granted the power of "lifetime" to guide object safety.
You will play a mysterious character named "Rustacean" and encounter all kinds of amazing tsundere bugs in the fight with "Rustc".
Conquer them, compile them, and gradually discover the truth behind the crash of the "C++" program.
Therefore, as a software designed in Rust language, SAS will use the characters in game Genshin Impact to name the version.
Version 1.0 will be codenamed "Amber".