Dec 22, 2023
Literate 어셈블리 언어
[Babbage's] The Chip Letter의 최근 판에서는 어셈블리 언어의 모호함에 대해 논의합니다. 그는 어셈블리 언어가 쓰여진 것보다 읽히는 경우가 더 많다고 지적했고 내 생각이 옳다고 생각합니다.
[Babbage's] The Chip Letter의 최근 판에서는 어셈블리 언어의 모호함에 대해 논의합니다. 그는 어셈블리 언어가 쓰여진 것보다 읽히는 경우가 더 많다고 지적했지만, 거의 모든 어셈블리 언어는 천공 카드에 80개의 열이 있고 6글자 기호만 관리할 수 있었던 시절부터 남겨진 모호함으로 인해 어려움을 겪고 있다고 지적했습니다. 컴퓨터의 제한된 메모리 공간에서. 예를 들어, 찾아보지 않고 ARM 명령어 FJCVTZS는 무엇을 수행합니까? 명령어의 전체 이름은 부동 소수점 Javascript 0을 향한 부호 있는 고정 소수점 반올림으로 변환입니다. 별로 도움이 되지 않습니다.
그러나 읽기 쉽게 만들어진 유능한 어셈블러를 작성하는 데 방해가 되는 것은 아무것도 없다는 생각이 들었습니다. 첫째, 대부분의 C 컴파일러는 일종의 asm 문을 허용하며 아마도 컴파일 타임 문자열 구성 및 매크로를 사용하여 이를 관리할 수 있습니다. 그러나 나는 더 나은 가능성이 있다고 생각합니다.
나는 때때로 새로운 CPU 아키텍처를 개발하기 때문에 솔직히 보기 흉한 범용 크로스 어셈블러를 가지고 있지만 꽤 잘 작동합니다. 이전에 이에 대해 이야기한 적이 있지만 전체 게시물을 읽고 싶지 않은 경우 몇 가지 간단한 트릭을 사용하여 표준적인 어셈블리 언어 형식을 C 코드로 변환한 다음 컴파일합니다. 결과 프로그램을 실행하면 원하는 기계어가 원하는 파일 형식으로 출력됩니다. 설정이 매우 쉽고 중간에 기계어 코드를 생성하는 멋진 C 프로그램이 있습니다. 원시 어셈블리보다 읽기 쉽지는 않지만 볼 필요는 없습니다. 하지만 거기서 프로세스를 시작하고 형식을 읽을 수 있게 만들면 어떻게 될까요?
시스템의 중심에는 soloasm.c에 있는 C 프로그램이 있습니다. 명령줄 옵션과 출력 파일 생성을 처리합니다. 단일 정수 인수를 사용하여 외부 함수인 genasm을 호출합니다. 해당 인수가 1로 설정되면 어셈블러가 첫 번째 단계에 있으며 레이블 값만 실수로 채워야 함을 나타냅니다. 패스가 2이면 실제로 코드가 들어 있는 배열을 채우는 것을 의미합니다.
해당 배열은 __solo_info 명령어(soloasm.h)에 정의되어 있습니다. 여기에는 메모리 크기, 코드에 대한 포인터, 프로세서의 워드 크기, 시작 및 끝 주소, 오류 플래그가 포함됩니다. 일반적으로 시스템은 어셈블리 언어 입력을 genasm 함수 내에 작성하는 일련의 함수 호출로 변환합니다. 하지만 이 경우에는 soloasm.c를 재사용하여 읽기 쉬운 어셈블리 언어를 만들고 싶습니다.
나는 이 모든 것을 오래 전에 썼지만, 쉽게 읽을 수 있는 어셈블리를 만들고 싶었기 때문에 쉽게 C++로 변환하기로 결정했습니다. 이를 통해 예를 들어 기호 테이블에 대한 멋진 데이터 구조를 사용할 수 있습니다. 그러나 나는 단지 시간을 고려하여 내가 가질 수 있는 모든 C++ 기능을 사용하지는 않았습니다.
기본 클래스는 프로세서에 대해 합리적으로 불가지론적이며, 예를 들어 전문적인 RCA 1802 어셈블러를 제공했습니다. 개념 증명일 뿐이므로 지침에 좀 더 일관되게 이름을 붙일 수 있고 다른 개선을 위한 여지도 많지만 이것이 내 요점을 전달합니다.
다음은 표준 어셈블러 구문을 사용하여 1802용으로 작성된 깜박이는 빛 프로그램의 발췌입니다.
이제 여기에 능숙한 어셈블러를 위해 작성된 것과 똑같은 내용이 있습니다.
글쎄요, 물론 설명과 기호가 있지만 여전히 그렇습니다. 비교하고 싶다면 두 파일을 모두 다운로드할 수 있습니다. 전체 프로젝트를 온라인에서도 찾을 수 있습니다.
아이디어는 간단합니다. 각 함수는 단순히 필요한 바이트로 배열을 채웁니다. 확실히 1802는 꽤 단순합니다. 명령어가 많고 모드가 복잡한 최신 프로세서에서는 이 작업을 수행하기가 더 어려울 것입니다. 그러나 불가능하지는 않습니다.
프로그래밍하는 동안이나 지침을 설정하는 동안 삶을 더 쉽게 만들기 위해 많은 일을 할 수 있습니다. 예를 들어, 100개의 NOP 명령어를 원하면 다음과 같이 작성할 수 있습니다.
for (int i = 0 ; i < 100 ; i++) NOP();
반면에 NOP에는 이를 수행하는 선택적 인수가 있습니다. C++ 컴파일러와 매크로 전처리기를 자유롭게 사용하여 생활을 더욱 편리하게 만들 수 있습니다. 예를 들어 1802의 일반적인 작업은 레이블과 같은 상수 값을 레지스터에 넣는 것입니다. lit1802.h 파일에는 이를 쉽게 해주는 매크로가 있습니다.