2010-01-31 2 views
3

이 코드는 아래에 있으며 ASM으로 변환하여 델파이에서도 사용하고 싶습니다.파스칼의 어셈블리에 포인터를 사용하여 코드 변환 - 델파이

var 
    FunctionAddressList: Array of Integer; 

type TFunction = function(parameter: Integer): Integer; cdecl; 

function Function(parameter: Integer): Integer; 
var 
    ExternFunction: TFunction; 
begin 
    ExternFunction := TFunction(FunctionAddressList[5]); 
    Result := ExternFunction(parameter); 
end; 

이 normaly 작동하지만, 나는 그것의 어셈블리 버전을하려고하면

void *FunctionAddressList; 

_declspec(naked) int Function(int parameter) 
{ 
    _asm mov eax, FunctionAddressList; 
    _asm jmp dword ptr [eax + 5 * 4]; 
} 

typedef int (*TFunction)(int parameter); 
int Function(int parameter) 
{ 
    TFunction ExternFunction = ((TFunction *)FunctionAddressList)[5]; 
    return ExternFunction(parameter); 
} 

그러나 : C++에서이 두 가지 방식으로 작동하기 때문에

function Function(parameter: Integer): Integer; cdecl; 
asm 
    mov eax, FunctionAddressList 
    jmp dword ptr [eax + 5 * 4] 
end; 

작동하도록되어 델파이에서는 작동하지 않습니다.

어셈블리 버전에서는 배열의 각 요소 사이의 오프셋 크기이므로 두 버전이 동일하므로 배열을 4로 곱합니다.

그래서 델파이에서 작동하지 않는 이유를 알고 싶습니다. Delphi에서 배열의 정수 값 사이의 오프셋 크기는 C++와 다릅니다.

1, 2, 4, 6, 8 등과 같이 많은 오프셋을 시도했습니다. 포인터의 배열, 포인터의 배열, 정수의 배열 등 많은 유형의 배열을 시도해 보았습니다. 많은 호출 규칙 및 cdecl이 비 asm 버전에서 작동하는 유일한 방법 이었지만 ASM에서는 모든 테스트가 작동하지 않았습니다.

감사합니다.

답변

3

첫 번째 테스트 응용 프로그램 오류 재현 :

var 
    FunctionAddressList: Array of Integer; 

function Bar(parameter: Integer): Integer; cdecl; 
begin 
    ShowMessage('Bar '+IntToStr(parameter)); 
end; 

function Foo(parameter: Integer): Integer; cdecl; 
asm 
    mov eax, FunctionAddressList 
    jmp dword ptr [eax + 5 * 4] 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    SetLength(FunctionAddressList, 6); 
    FunctionAddressList[5]:= Integer(@Bar); 
    Foo(25); 
end; 

바 주소가 올바르게 정의되어 있지만 문제는 델파이 컴파일러는 푸 대한 프롤로그와 에필로그를 생성하는, 그래서 실제 푸 코드는

0046CD30 55    push ebp 
0046CD31 8BEC    mov ebp,esp 
Unit1.pas.46:    mov eax, FunctionAddressList 
Unit1.pas.47:    jmp dword ptr [eax + 5 * 4] 
0046CD3B 5D    pop ebp 
0046CD3C C3    ret 
입니다

결과적으로 스택이 손상되고 매개 변수가 잘못되어 바 반환 주소가 잘못되었습니다. 여전히 트릭을하고 싶다면

function Foo(parameter: Integer): Integer; cdecl; 
asm 
    pop ebp 
    mov eax, FunctionAddressList 
    jmp dword ptr [eax + 5 * 4] 
end; 
+1

지금 C++을 사용하지는 않지만, C++ (Visual C++을 사용하고 있다고 가정합니다) 코드는 알몸 함수에 대해서도 인수를 인수로 가정합니다 . cdecl 호출 규칙을 사용하는 naked 함수에서 인수에 도달하려면 프롤로그 및 에필로그를 직접 작성해야합니다 (asm). 여기서 인수를 필요로하지 않으므로 주소 목록의 함수에 스택에 전달하므로 사용자가하지 마십시오. – kludg

1

Array of Integer은 귀하가 생각하는 것과 다릅니다. 자동으로 관리되는 동적 배열입니다.

FunctionAddressList: ^Pointer;을 사용하여 동일하게 시도해야하지만 수동 할당 및 할당 해제가 필요합니다.

+0

FunctionAddressList를 할당했지만 여전히 작동하지 않습니다. '* 4'값을 다른 값으로 변경해야합니까? –

+0

@Edward - 4를 사용하지 말고 SizeOf (포인터)를 사용하십시오. 64 비트 시스템이라면 4가 아닐 것입니다. –

관련 문제