2013-04-13 1 views
9

저는 최근 자신 만의 프로그래밍 언어를 만드는 궁극적 인 목표를 가지고 어셈블리 프로그래밍 세계에 몰두하려고 노력하고 있습니다. 첫 번째 실제 프로젝트가 C로 작성된 간단한 어셈블러가되어 x86 머신 언어의 아주 작은 부분을 어셈블하고 Windows 실행 파일을 만들 수 있기를 바랍니다. 매크로도 링커도 없습니다. 그냥 조립.C에서 간단한 어셈블러를 만들고 싶습니다. 어디에서 시작해야합니까?

종이에 보면 충분히 간단 해 보입니다. 어셈블리 코드가 들어 오면 기계 코드가 나옵니다.

그러나 모든 세부 사항을 생각하자마자 갑자기 매우 위압적입니다. 운영 체제에서 요구하는 규칙은 무엇입니까? 어떻게 데이터를 정렬하고 점프를 계산합니까? 실행 파일의 내부는 어떻게 생겼습니까?

나는 실종되었다. 이것에 대한 자습서가 없기 때문에 인기있는 어셈블러의 소스 코드를 찾아 볼 수는 없었습니다 (다시 시도해 볼 의향이 있습니다).

여기에서 나는 어디로 가나 요? 어떻게 그랬습니까? 이 주제에 대한 훌륭한 자습서 또는 문헌이 있습니까?

+1

뭔가 생각해보십시오 : 사용자가 적절한 지침을 사용하고 있는지 확인하기위한 유한 오토마타, 프로그래머가 작성한 내용이 올바른지 확인하기 위해 파서가 필요합니다. 걱정할 필요가있는 많은 시스템 측면의 것들이 있지만, 또한 알고 있어야 할 많은 계산 이론이 있습니다. –

+1

어쩌면 당신은 [NASM] (http://www.nasm.us/)와 같은 패키지를 연구해야 할 것입니다. –

+0

8086 리소스에 대해서는 [코드 골프에 대한이 도전 과제] (http://codegolf.stackexchange.com/questions/4732/emulate-an-intel-8086-cpu)와 하위 세트를 사용하는 너무 짧지 않은 샘플 프로그램을 확인하십시오. 원본 및 바이너리 형식 모두에서 8086 IMO 1979 매뉴얼이 시작됩니다. ... 또한 [내 어셈블리 리소스 위키 질문] (http://stackoverflow.com/a/7203667/), 특히 원시적 인 어셈블러에 대한 자세한 설명을 제공하는 "PDP-1_Macro.pdf"파일을 살펴보십시오 . –

답변

3

당신이 찾고있는 것은 튜토리얼이나 소스 코드가 아니며 사양입니다. http://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx

실행 파일의 사양을 이해했으면 프로그램을 작성하여 작성하십시오. 실행 파일은 가능한 한 간단해야합니다. 다음에을 마스터하면 명령 이름과 숫자 인수를 읽는 간단한 라인 지향 파서를 작성하여 exe에 연결하는 코드 블록을 생성 할 수 있습니다. 나중에 심볼, 분기, 섹션을 원하는대로 추가 할 수 있으며, 이는 과 같은 것입니다.

P.S. Carl Norum은 위의 코멘트에서 좋은 점을 가지고 있습니다. 목표가 고유 한 프로그래밍 언어를 만드는 것이라면 어셈블러 작성 방법을 배우는 것이 중요하지 않으므로 작성하려는 언어가 어셈블리 언어가 아니라면 시작하는 것이 옳은 방법이 아닙니다. 이미 어셈블러 소스에서 실행 파일을 생성하는 어셈블러가 있으므로 컴파일러가 어셈블러 소스를 생성 할 수 있으므로 어셈블러를 다시 만들지 않아도됩니다. 또는 LLVM과 같은 것을 사용할 수도 있습니다. 이것은 컴파일러 구축과 관련된 많은 문제들을 해결할 것입니다. 확률은 매우 작아서 자신의 프로그래밍 언어를 실제로 만들지는 않겠지 만 처음부터 다시 시작할 필요가 없으면 훨씬 작아집니다. 목표가 무엇인지 결정하고이를 달성하는 데 사용할 수있는 최상의 도구를 사용하십시오.

4

당신은 LLVM을 봐야합니다. llvm은 모듈러 컴파일러 백엔드입니다. 가장 인기있는 프런트 엔드는 C/C++/Objective-C 컴파일을위한 Clang입니다. LLVM에 대한 좋은 점은 관심있는 컴파일러 체인의 일부를 선택하고 나머지는 모두 무시한다는 것입니다. 자신 만의 언어를 만들고, LLVM 내부 표현 코드를 생성하는 파서를 작성하고, 무료로 모든 중간 계층 타겟 독립적 최적화를 얻고 많은 다른 타겟으로 컴파일하려고합니다. 일부 이국적인 CPU 용 컴파일러에 흥미가 있으면 LLVM 중간 코드를 사용하고 어셈블을 생성하는 컴파일러 백엔드를 작성하십시오. 최적화 기술, 자동 스레딩에 대한 아이디어가 있다면 LLVM 중간 코드를 처리하는 중간 계층을 작성하십시오. LLVM은 GCC와 같은 독립형 바이너리가 아닌 라이브러리 모음이므로 프로젝트 자체에서 사용하기가 매우 쉽습니다.

11

나는 약간의 글을 써 왔지만 (어셈블러와 디스어셈블러) 나는 x86으로 시작하지 않을 것이다. x86 또는 다른 명령어 세트를 알고있는 경우 짧은 명령 (저녁/오후)으로 다른 명령어 세트의 구문을 습득하고 학습 할 수 있습니다.어셈블러 (또는 디스어셈블러)를 작성하는 것은 확실히 당신에게 빠른 명령어 세트를 가르쳐 줄 것이고, 그 레벨에서 마이크로 코드를 검사하지 않은 많은 명령어를 가진 많은 노련한 어셈블리 프로그래머보다 명령어가 더 잘 설정된다는 것을 알게 될 것입니다. msp430, pdp11 및 thumb (thumb2 확장이 아님) (또는 mips 또는 openrisc)은 시작하기에 좋은 곳으로 지나치게 복잡하지는 않습니다. 지나치게 복잡하지는 않습니다.

먼저 디스어셈블러를 권장합니다. 팔 또는 엄지 또는 mips 또는 openrisc와 같은 고정 길이 명령어 세트. 그렇지 않다면 적어도 디스어셈블러를 사용하고 (확실히 어셈블러, 링커 및 디스어셈블러가있는 명령어 세트를 선택하십시오.) 연필과 종이로 관계를 이해하십시오 기계 코드와 어셈블리, 특히 브랜치 사이에는 일반적으로 프로그램 카운터와 같은 하나 이상의 단점이 있습니다. 오프셋이 추가 될 때 앞쪽에있는 명령이거나 나머지 비트를 얻기 위해 때로는 바이트가 아닌 전체 명령에서 측정합니다.

C 프로그램으로 텍스트를 구문 분석하여 지침을 읽는 것은 꽤 쉽습니다. 더 힘든 일이지만 교육적인면에서 bison/flex를 사용하고 프로그래밍 언어를 배워서 해당 도구가 코드에 인터페이스하여 어디서 무엇을 발견했는지 알려주는 파서를 만들 수 있습니다.

어셈블러 자체는 꽤 간단합니다. ASCII 코드를 읽고 기계어 코드 비트를 설정하십시오. 분기 및 기타 PC 관련 명령어는 소스/테이블을 여러 번 통과하여 완전히 해결할 수 있기 때문에 조금 더 고통 스럽습니다.

mov r0,r1 
    mov r2 ,#1 

어셈블러는 당신이 뭔가 아닌 흰색에 도달 할 때까지 공백 (공백과 탭)을 버리고 선 (0xD 또는 라인이 0xa는 먹이를 캐리지 리턴을 따라 바이트로 정의되는)에 대한 텍스트를 구문 분석 시작 공간, 다음 stnncmp 알려진 니모닉. 하나를 친 다음 해당 명령어의 가능한 조합을 구문 분석하면, mov가 공백을 비 공백으로 건너 뛰고 난 후 위의 간단한 경우에, 아마도 가장 먼저 발견되는 것은 레지스터 여야하고, 선택적 공백, 그리고 나서 콤마. 공백과 쉼표를 제거하고 그것을 문자열 테이블과 비교하거나 그냥 구문 분석하십시오. 해당 레지스터가 완료되면 쉼표가있는 곳을지나 가서 다른 레지스터 또는 즉각적인 것으로 말할 수 있습니다. 즉각적인 경우 # 기호가 있어야한다고 말하면 레지스터에 대문자 'r'을 사용해야합니다. 그 레지스터 나 즉각적인 구문 분석 후에 라인에 should should not가없는 라인에 다른 것이 없는지 확인하십시오. 이 지침서의 기계어 코드를 만들거나 가능한 한 많이 작성한 다음 다음 줄로 이동하십시오. 지루할 수 있지만 아스키 구문 분석은 어렵지 않습니다 ...

적어도 작성한 기계 코드/데이터를 축적하는 테이블/어레이와 지침을 불완전한 것으로 표시하는 몇 가지 방법이 필요합니다. , PC 관련 지시 사항은 이후 패스에서 완료해야합니다. 발견 된 레이블과 발견 된 기계 코드 테이블의 주소/오프셋을 수집하는 테이블/어레이가 필요할 것입니다. 또한 명령에서 대상/소스로 사용 된 레이블과 부분적으로 완료된 명령을 포함하는 테이블/배열의 오프셋이 함께 사용됩니다. 첫 번째 단계 후에 소스 또는 대상으로 사용되는 레이블과 모든 레이블 정의를 일치시킬 때까지이 테이블로 돌아가 레이블 정의 주소/오프셋을 사용하여 문제의 명령어까지의 거리를 계산 한 다음 작성을 완료하십시오 그 명령의 기계어 코드. (기계 코드 작성을 마치기 위해 나중에 다시 돌아 왔을 때 어떤 종류의 인코딩이 필요한지 기억하기 위해 일부 디스 어셈블리가 필요할 수도 있고 다른 방법을 사용할 수도 있습니다).

다음 단계는 허용하려는 항목이 여러 개인 경우 허용합니다. 이제 어셈블러가 해결하지 못하는 레이블을 가져야 만 출력물에 자리 표시자를 남겨두고 가장 먼 점프/분기 명령의 맛을 만들어야합니다. 대상이 얼마나 멀리 떨어져 있는지 알 수 없으므로 더 나빠질 것입니다.그런 다음 생성/사용하도록 선택한 출력 파일 형식이 있습니다. 링커가 대부분 간단하지만 어셈블러에 있던 것보다 더 힘든 최종 PC 상대 명령어에 대한 기계 코드를 작성해야합니다. 그 자체.

참고 : 어셈블러 작성은 프로그래밍 언어 작성과 컴파일러 작성, 별도의 작업, 다른 문제점에 반드시 관련되는 것은 아닙니다. 실제로 새로운 프로그래밍 언어를 만들고 싶다면 기존 명령어 세트에 기존 어셈블러 만 사용하면됩니다. 물론 필수는 아니지만, 대부분의 가르침과 튜토리얼은 프로그래밍 언어에 bison/flex 접근법을 사용할 예정이며, 시작하기 위해 사용할 수있는 시작 컴파일러 클래스에 대한 대학 강의 노트/리소스가 많이 있습니다. 귀하의 언어 기능을 추가하는 스크립트. 중간과 뒤쪽 끝은 앞쪽 끝보다 큰 도전입니다. 이 주제에 대한 책과 많은 온라인 자료가 있습니다. 다른 대답에서 언급했듯이 llvm은 새로운 프로그래밍 언어를 만드는 나쁜 곳이 아니며 중간 및 백엔드가 완료되면 프로그래밍 언어 그 자체 인 프론트 엔드에만 집중하면됩니다.

관련 문제