Delphi Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
델파이 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
FreePascal/Lazarus
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
델마당
볼랜드포럼 광고 모집

델파이 Q&A
Delphi Programming Q&A
[16007] Re:C++빌더님. 불가능할 것 같긴한데요, 혹시나 해서 여쭈어 봅니다
빌더(TWx) [builder] 1749 읽음    2019-03-04 00:33
코딩 님이 쓰신 글 :
: procedure f(var v);
: begin
:
: end;
:
: procedure TForm1.Button1Click(Sender: TObject);
: var
:     str: string;
:     i: integer;
: begin
:     i := 777;
:     str := 'hello';
:     f(i);
:     f(str);
: end;
:
:
: v가 타입 없는 var로 되어 있는데요
:
: 프로시져 f 에서 v 의 타입이 string 인지 integer 인지 알수 있는 방법이 있을까요?
:
: 델마당에 올라온 질문인데요
: 제 생각으론 아무리 생각해봐도 불가능 할것 같긴한데요
: 혹시나 해서 여쭈어 봅니다.
:



답변:


도움말만 봐도 알수 있는 단순한 컴포넌트 사용법 관련된 글이면 한번 읽고 지나쳤을 텐데...
기술적인 부분이라 답변 글 남깁니다.


CPU의 고유한 ID 값을 알아내기 위해 메인보드의 롬바이오스 SMB Bios 펌웨어 테이블 파싱이 필요하고
펌웨어 테이블의 자료구조 상... 테이블 파싱을 위해 T** two pointer 타입의 포인터 연산이 자주 사용되는데

C++에선 T1 ** 타입을 T2 *& 으로 포인터에 대한 레퍼런스 타입으로 치환해서 포인터 연산을 간략하게 할 수 있으나

     T1 ** p;
     T2 v = *((T2 *&)p)++;

T** two 포인터 연산을 파스칼로 작성하면 코드가 지져분해지므로 속편하게 예제는 어셈블리 코드로 작성 합니다.


Object Inspector 를 통해 다양한 타입을 참조할 수 있는데... Boolean 타입을 예로 들어 봅시다.
부울형의 경우 True, False 값을 Object Inspector 에서 표시해 주죠.
이와 같은 메카니즘이 가능한 것은 델파이 컴파일러에 의해서 Rtti 정보가 바이너리로 Emit 되기 때문인데요.
(Object Inspector를 통해서 보여지는 타입 정보들은 컴파일러에 의해 바이너리로 Emit 된 Rtti 정보 중에서
published 된 극히 일부분에 불과함)

Boolean 타입의 정보를 런타임 중에 바이너리에서 직접 찾아서 표시하는 예를 들어 봅시다.

function GetBooleanType(): string;
type PS = PShortString;
var tn, v1, v2: DWORD;
begin
  asm
    mov esi, $1000
    push 0
    call GetModuleHandle
    add esi, eax
    mov esi, [esi]
    lea esi, [esi + 1]
    mov tn, esi
    mov al, [esi]
    movzx eax, al
    lea esi, [eax + esi + 14]
    mov v1, esi
    mov al, [esi]
    movzx eax, al
    lea esi, [eax + esi + 1]
    mov v2, esi
  end;
    Result := 'typeName: ' + PS(tn)^ + ' ,v1: ' + PS(v1)^ + ' ,v2: ' + PS(v2)^;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Add( GetBooleanType() );
end;






위의 경우는 Boolean 타입 하나만 예로 든 거고...

class, record, virtual method, propery, message handler, event handler, class method, interface method 등등
델파이로 컴파일 되어있는 바이너리의 모든 타입 정보들을 리버스 엔지니어링으로 바이너리로 부터 직접 알아 낼수 있지요.


그리고...


procedure f(var v);
begin

end;

procedure TForm1.Button1Click(Sender: TObject);
var
     str: string;
     i: integer;
begin
     i := 777;
     str := 'hello';
     f(i);
     f(str);
end


procedure f(var v); 에서 v 의 타입을 알아내는 건...

컴파일러에 의해서 타입 정보가 넘어오지 않아서 일견 보기에는 불가능해 보일 수도 있으나
넘어온 파라미터 v 가 string 과 integer 둘 중에 하나라는 조건이 주어지고
델파이 컴파일러 내부구조를 알고 있으면 이 또한 가능 합니다.


procedure Foo(var V);
var mi: array[0..27] of Byte;
begin
  asm
    mov esi, V
    mov esi, [esi]
    lea esi, [esi - 12];
    lea edi, mi
    push 28
    push edi
    push esi
    call VirtualQuery
    mov [edi + 16], eax
    and eax, eax
    je @skip
    add esi, 12
    and dword ptr [edi + 20], $24
    mov dword ptr [edi + 20], esi
    je @next
    cmp dword ptr[esi - 12], $204b0
    jnz @next
    mov byte ptr[edi + 16], 2
    jmp @skip
  @next:
    mov byte ptr[edi + 16], 1
  @skip:
  end;

  if mi[16] = 1 then
    Form1.Memo1.Lines.Add(Format('type: integer, value: %d', [PInteger(@mi[20])^]))
  else if mi[16] = 2 then
    Form1.Memo1.Lines.Add(Format('type: string, value: %s', [PChar(PDword(@mi[20])^)]))
  else
    Form1.Memo1.Lines.Add('Fail: VirtualQuery()')
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  s: string;
  i: integer;
begin
  i := 777;
  s := 'hello';

  Foo(i);
  Foo(s);
end;







모든 코드는 Rad studio 10.3.1 기준으로 작성.



+ -

관련 글 리스트
16006 C++빌더님. 불가능할 것 같긴한데요, 혹시나 해서 여쭈어 봅니다 코딩 1358 2019/02/28
16141     Re:Overload를 사용하시면 쉬울듯.... 첫눈 633 2020/12/08
16007     Re:C++빌더님. 불가능할 것 같긴한데요, 혹시나 해서 여쭈어 봅니다 빌더(TWx) 1749 2019/03/04
16009         Re:Re:C++빌더님. 불가능할 것 같긴한데요, 혹시나 해서 여쭈어 봅니다 코딩 1433 2019/03/06
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.