0

16 비트 레지스터 기반 가상 컴퓨터가 있는데 실제 x86 컴퓨터 코드로 컴파일하는 단계는 무엇입니까? 컴파일 된 코드를 다른 실행 파일/DLL과 링크 할 수 있어야하는 경우가 아니면 을 JIT 컴파일러로 만들지 않습니다.VM 고유 코드를 x86 컴퓨터 코드로 컴파일하는 방법은 무엇입니까?

VM은 프로젝트에 VM을 추가하면 특수 언어 구문을 추가 할 수 있도록 만들어졌습니다. (예를 들어 게임 엔진에 임베드 된 경우 엔티티 개체 유형이 추가 될 수 있고 엔진의 여러 C 함수가 노출 될 수 있습니다.) 그러면 코드가 노출 된 특정 C 함수에 완전히 종속되거나 노출 된 C++ 클래스를 임베디드 된 응용 프로그램에서 사용할 수 있습니다.

스크립트 코드가 VM 바이트 코드에서 기본 EXE로 컴파일되는 경우 이러한 종류의 "연결"이 가능합니까?

또한 Lua의 VM과 마찬가지로 모든 기본 변수가 거대한 C 배열 인 "레지스터"에 저장되므로 레지스터 기반입니다. 레지스터 포인터는 범위가 변경 될 때 증가 또는 감소하므로 레지스터 번호는 상대적이며 스택 포인터와 유사합니다. 예컨대 :

int a = 5; 
{ 
    int a = 1; 
} 

수 있습니다, 가상 머신 의사 어셈블리 :

mov_int (%r0, $5) 

; new scope, the "register pointer" is then incremented by the number 
; of bytes that are used to store local variables in this new scope. E.g. int = 4 bytes 
; say $rp is the "register pointer" 

add  (%rp, $4) ; since size of int is usually 4 bytes 
        ; this is if registers are 1 bytes in size, if they were 
        ; 4 bytes in size it would just be adding $1 

mov_int (%r0, $1) ; now each register "index" is offset by 4, 
        ; this is now technically setting %r4 
        ; different instructions are used to get values above current scope 

sub (%rp, $4) ; end of scope so reset %rp 

이 부분에 대한 내 질문은 내가 이런 종류의 스택 포인터를 사용하는 것입니까? 기본 포인터? 이 개념을 대체하기 위해 무엇을 사용할 수 있습니까?

+1

Q & A 사이트에 대한 귀하의 질문은 너무 광범위합니다. 책이나 대학 과정이 필요합니다. – EJP

+0

나는 그것을 훨씬 덜 넓고 분명하게 만들었고, 그래서 그것은 2 개의 간단한 질문으로 귀결된다. – Accumulator

+0

나는 여기에 실질적인 대답할만한 질문이 있다고 생각하지만, 당신이 묻고있는 것을 정확히 이해하기 란 거의 어렵지 않습니다. 나는 너를 돕고 싶다.하지만 질문을 조금이라도 더 바꾸려고하면 ... 너를 도울 수있게 도와 준다.) – Cauterite

답변

0

VM은 프로젝트에 VM을 추가하면 특수 언어 구문을 추가 할 수 있도록 만들어졌습니다. (예를 들어 게임 엔진에 임베드 된 경우 엔티티 개체 유형이 추가 될 수 있고 엔진의 여러 C 함수가 노출 될 수 있습니다.) 그러면 코드가 노출 된 특정 C 함수에 완전히 종속되거나 노출 된 C++ 클래스를 임베디드 된 응용 프로그램에서 사용할 수 있습니다.

이러한 종류의 교차 언어 인터페이스를 구현하는 방법은 다양합니다. VM 바이트 코드 또는 네이티브 머신 코드가 실행 중인지 여부는 매우 낮은 오버 헤드로 인터페이스가 필요하지 않는 한 많은 문제가되지 않습니다. 가장 중요한 고려 사항은 언어의 특성, 특히 정적 또는 동적 입력이 있는지 여부입니다.

일반적으로 이러한 (당신은 그들에 대해 잘 알고 있어야 이미 수 있음) 가장 일반적인 두 가지 접근 방식을하고 있습니다 말하기 :

  • (가) '외국 기능 인터페이스'접근, 어디 언어를/runtime은 C에서 자동으로 함수와 데이터를 래핑하는 기능을 제공합니다. 예제에는 LuaJIT FFI, js-ctypesP/Invoke이 포함됩니다. 대부분의 FFI는 CDECL/STDCALL 기능 및 POD 구조에서 작동 할 수 있습니다. 일부는 C++ 또는 COM 클래스에 대해 다양한 수준의 지원을 제공합니다.

  • (b)에 런타임은 수동으로 해당 언어로 사용하기 위해 객체/구성 조작하는 데 사용할 수있는 C API를 노출하는 '런타임 API'접근. 루아는이 (example)에 대한 광범위한 API를 Python과 같이 가지고 있습니다.스크립트 코드는 기본 EXE에 VM 바이트 코드로 컴파일 된 경우

는 방법 "연결"이런 종류의 가능한 것입니까?

예를 들어, 외부 함수 주소를 생성 된 machinecode에 저장하십시오. 글쎄, 적절한 FFI 인프라가 있다면, 공유 라이브러리 가져 오기가 어떻게 작동하는지 (주소 테이블 가져 오기, 재배치, 픽스 업 등) 알고있는 한, 그렇게 할 수있는 이유가 없습니다.

공유 라이브러리에 대해 잘 모르는 경우 해당 영역을 연구하면서 컴파일러에서 FFI를 구현할 수있는 방법을 훨씬 더 명확하게 알기 시작할 것입니다.

예를 들어 LoadLibrary(), GetProcAddress()과 같이 약간 더 역동적 인 접근 방법을 사용하는 것이 더 쉬울 경우 함수 포인터를 언어 개체로 포장하십시오.

문제의 언어/VM에 대해 알지 못해서 더 구체적인 제안을하는 것은 매우 어렵습니다.


[...]이 부분에 대한 내 질문은, 내가 이런 종류의 스택 포인터를 사용하는 것? 기본 포인터? 이 개념을 대체하기 위해 무엇을 사용할 수 있습니까?

이 '레지스터 배열'체계의 목적이 무엇인지 모릅니다.

렉시 컬 스코핑을 사용하는 언어에서는 함수를 컴파일 할 때 일반적으로 본문에 선언 된 모든 변수를 열거하고 모든 변수를 담을 수있는 충분한 크기의 스택 공간을 할당한다는 사실을 이해합니다 (CPU 레지스터의 복잡한 항목은 무시함). 배당). 코드는 스택 포인터 또는 (더 자주) 기본 포인터를 사용하여 이러한 변수를 지정할 수 있습니다.

내부 범위의 변수가 예제와 같이 바깥 쪽 범위에있는 변수를 음영 처리하는 경우 컴파일러에 관한 한 서로 다른 변수이기 때문에 스택에 별도의 메모리 공간이 할당됩니다.

VM이 사용하는 모든 구성표의 이유를 이해하지 못하면 어떻게 기계 코드로 변환해야하는지 제안 할 수 없습니다. 어쩌면 바이트 코드 컴파일러 프로그래밍 경험이 많은 사람이 여러분에게 답을 줄 수 있습니다.

그러나 VM의 접근법이 실제로 설명한 것과 비슷할 수 있습니다.이 경우 머신 코드 컴파일을 실제로 적용하는 것이 실제로 매우 간단해야합니다. 가상 로컬 변수 메모리 공간을 스택으로 변환하는 문제입니다. 공간.

1

질문을 올바르게 이해했다면 예, SP/BP 등을 사용해야합니다. 이것이 네이티브 머신 코드로 컴파일되는 것을 의미합니다 : 프로그램의 상위 레벨 동작을 실행중인 운영 체제의 규칙을 따르는 동일한 기계 명령어로 변환합니다.

따라서 어셈블러에서 호출 한 경우 호스트 제공 함수를 호출 할 때와 동일한 작업을 수행해야합니다.일반적으로 함수 인수의 값을 적절한 레지스터에 집어 넣거나 스택에 밀어 넣고 필요에 따라 변환 한 다음 CALL 또는 JMP 명령어를 생성하거나 CPU가 실제로 주어진 함수의 메모리 주소로 점프하기를 기대하는 것이 무엇이든간에.

호스트가 제공하는 포인터 매핑 기능을 사용하려면 함수 이름 테이블이 있어야하며 거기에서 주소를 확인하십시오.

일단 함수가 반환되면 필요에 따라 함수가 반환 한 값을 내부 형식으로 변환하고 기쁜 마음으로 이동하십시오. (이것은 기본적으로 모든 "외부 함수 인터페이스"라이브러리가 내부적으로 수행하는 것입니다.)

언어 및 사용되는 언어에 따라 여기에서 속일 수도 있습니다. 자신의 내부 의사 스택을 사용할 수 있으며 "call native function"명령을 추가하면됩니다. 이 명령은 함수에 대한 정보를 매개 변수로받습니다 (예 : 어떤 매개 변수 유형을 가져오고 반환하는지, 함수 포인터를 찾는 방법). 그러면 외부 함수 인터페이스 라이브러리를 사용하여 실제 함수 호출을 수행합니다.

네이티브 함수를 호출하면 약간의 오버 헤드가 발생하지만 VM을 그대로 유지하면서 사람들이 네이티브 코드로 호출하여 응용 프로그램과 통합 할 수 있음을 의미합니다.