اسمبلر داخلی
معرفی
이 문서는 Wave 언어에서 제공하는 인라인 어셈블리 기능에 대해 설명합니다. 인라인 어셈블리는 Wave가 제공하는 기능 중 하나로, 고수준 언어가 갖는 편의성과 구조를 유지하면서도 저수준 하드웨어 제어에 직접 접근할 수 있도록 설계된 문법입니다.
일반적인 Wave 코드로는 표현하기 어려운 레지스터 조작, 메모리 주소 단위 접근, 특정 CPU 명령어 실행과 같은 작업을 가능하게 하며, 성능 최적화가 중요하거나 하드웨어 및 아키텍처에 강하게 의존하는 코드가 필요한 상황에서 활용됩니다. 이 기능을 통해 Wave는 단순한 고수준 언어를 넘어, 시스템 프로그래밍 영역까지 포괄할 수 있습니다.
دستور زبان پایه
인 라인 어셈블리는 asm { ... } 블록을 통해 작성합니다.
이 블록 안에는 실제로 실행될 어셈블리 명령어와, Wave 변수와 CPU 레지스터를 연결하기 위한 입력·출력 매핑이 함께 정의됩니다.
اسم {
"دستورات اسمبلر" // کد واقعی اسمبلر (یک دستور در هر خط)
...
in("رجیستر") مقدار // نگاشت رجیستر ورودی
out("رجیستر") متغیر // نگاشت رجیستر خروجی
}
어셈블리 명령어는 문자열 형태로 작성되며, 실제 CPU에서 실행되는 저수준 명령어를 그대로 기술합니다. 여러 줄로 작성할 수 있으며, 각 줄에는 하나의 명령어만 작성하는 것을 원칙으로 합니다.
예를 들어 다음과 같은 형태로 사용할 수 있습니다.
"mov rax, 1"
"syscall"
in("레지스터") 값 구문은 Wave 변수나 표현식의 값을 지정한 CPU 레지스터에 로드하기 위해 사용됩니다.
이를 통해 어셈블리 코드에서 해당 레지스터를 입력값으로 사용할 수 있습니다.
아래 예시는 변수 s의 값을 x86-64 규약에서 첫 번째 syscall 인자 레지스터인 rdi에 전달하는 경우입니다.
in("rdi") s
반대로 out("레지스터") 변수 구문은 지정한 레지스터에 들어 있는 값을 Wave 변수로 가져오는 역할을 합니다.
어셈블리 실행 결과를 Wave 코드에서 사용해야 할 때 이 방식을 사용합니다.
다음 예시는 syscall 호출 이후 반환값이 저장되는 rax 레지스터의 값을 변수 ret에 저장하는 경우입니다
out("rax") ret
간단한 예제
아래 예제는 Linux x86-64 환경에서 syscall을 이용해 문자열을 표준 출력으로 출력하는 간단한 코드입니다.
fun main() {
var msg_ptr: ptr<i8> = "سلام از syscall!\n";
var ret_val: i64;
asm {
"mov rax, 1"
"syscall"
in("rdi") 1
in("rsi") msg_ptr
in("rdx") 20
out("rax") ret_val
}
}
이 예제에서 Wave 코드는 문자열의 포인터와 길이를 레지스터에 직접 설정하고, 시스템 콜을 호출하여 출력 작업을 수행합니다.
시스템 콜의 반환값은 rax 레지스터를 통해 전달되며, out 구문을 통해 Wave 변수로 다시 가져옵니다.
ملاحظات
인라인 어셈블리는 Wave의 타입 안정성과 추상화를 의도적으로 우회하는 기능입니다. 잘못된 명령어 사용이나 레지스터 설정 오류가 발생할 경우, 프로그램이 비정상 종료되거나 undefined behavior가 발생할 수 있습니다.
in과 out을 통한 레지스터 매핑 자체는 컴파일 타임에 검증되지만, 어셈블리 명령어의 의미적 유효성이나 실행 결과까지 보장되지는 않습니다.
따라서 인라인 어셈블리를 사용할 때에는 대상 아키텍처와 호출 규약, 그리고 명령어의 동작을 정확히 이해하고 있어야 합니다.