2013-06-25 3 views
1

내 문제는 다음과 같습니다. 나는 예를 들어 말, 코드 유닛이 다양한 C의 파일로 구성이VxWorks의 함수 호출 재정의

  • file1.c에서
  • 와 file2.c
  • file3.c 모든 고유에 GCC로 컴파일

객체 "object.o"는 다른 객체와 연결되어 VxWorks에서 실행되는 실행 파일 "application.out"을 마지막에 제공합니다.

"object.o"에 대한 단위 테스트를하고 있으므로 코드를 통해 가능한 모든 방법을 자극해야합니다. 특히 오류 발생을 시뮬레이트하기 위해 원본 함수 대신 모의 함수를 실행해야하는 상황이 있습니다. 예를 들어, 실행 중에 "func_caller"함수가 "func_called"(정적으로 선언 된) 함수를 호출한다는 것을 테스트하려고한다고 가정하십시오.

원본 코드를 수정하고 싶지 않으므로 "func_called"가 호출 될 때 실제로 다른 모의 함수 "func_called_mock"을 실행하는 방법으로 명령 포인터를 조작하는 방법이 있는지 궁금합니다. 호출자 "func_caller"는 아무 것도 알지 못합니다.

미리 감사드립니다.

답변

2

함수 호출을 재정의하는 가장 직접적인 방법은 VxWorks의로드 시간 연결을 사용하는 것입니다.

file1.c에서 :

#include <stdio.h> 

int function1 (void); 

int function1() 
{ 
    printf ("function1 called\n"); 

    return 1; 
} 

와 file2.c :

#include <stdio.h> 

int function2 (void); 

int function2() 
{ 
    printf ("function2 called\n"); 

    return 2; 
} 

file3.c :

int function1 (void); 
int function2 (void); 

int function3 (void); 

int function3() 
{ 
    function1(); 
    function2(); 

    return 0; 
} 

mock.c :

#include <stdio.h> 

int function1 (void); 
int function2 (void); 

int function1() 
{ 
    printf ("mock function1 called\n"); 

    return 1; 
} 

int function2() 
{ 
    printf ("mock function2 called\n"); 

    return 2; 
} 
다음 소스를 고려

개체를로드하면 그 기능이 전역 기호 테이블에 추가됩니다.

-> ld < file1.o 
value = 273740816 = 0x1050f410 
-> lkup "function" 
function1     0x108b0000 text  (file1.o) 
value = 0 = 0x0 
-> 

는 심볼 테이블에 이미 기능을 사용하는 개체를로드 , 각 호출은 즉시 테이블의 심볼과 관련된 마지막 주소로 해결 될 것입니다. l()가 유용하게 기능 명을 표시

-> ld < file2.o 
value = 292535232 = 0x116fbbc0 
-> ld < file3.o 
value = 292537592 = 0x116fc4f8 
-> lkup "function" 
function1     0x108b0000 text  (file1.o) 
function2     0x108d0000 text  (file2.o) 
function3     0x108f0000 text  (file3.o) 
value = 0 = 0x0 
-> l function3 
      function3: 
0x108f0000 55      PUSH   EBP 
0x108f0001 89 e5     MOV   EBP, ESP 
0x108f0003 56      PUSH   ESI 
0x108f0004 57      PUSH   EDI 
0x108f0005 e8 f6 ff fb ff   CALL   function1 
0x108f000a e8 f1 ff fd ff   CALL   function2 
0x108f000f 31 c0     XOR   EAX, EAX 
0x108f0011 5f      POP   EDI 
0x108f0012 5e      POP   ESI 
0x108f0013 89 ec     MOV   ESP, EBP 
value = 0 = 0x0 
-> function3 
function1 called 
function2 called 
value = 0 = 0x0 
-> 

있지만, 어떤 심볼은 실제로 개체 메모리에로드되지 않는다. 대신, 함수와 관련된 마지막 주소에 대한 호출이로드됩니다. 따라서 이전에로드 된 함수는 동일한 이름의 다른 함수를로드하여 재정의 할 수 있습니다.

-> unld "file3.o" 
value = 0 = 0x0 
-> ld < mock.o 
value = 292537592 = 0x116fc4f8 
-> ld < file3.o 
value = 292539496 = 0x116fcc68 
-> lkup "function" 
function1     0x108f0000 text  (mock.o) 
function1     0x108b0000 text  (file1.o) 
function2     0x108f0020 text  (mock.o) 
function2     0x108d0000 text  (file2.o) 
function3     0x10910000 text  (file3.o) 
value = 0 = 0x0 
-> l function3 
      function3: 
0x10910000 55      PUSH   EBP 
0x10910001 89 e5     MOV   EBP, ESP 
0x10910003 56      PUSH   ESI 
0x10910004 57      PUSH   EDI 
0x10910005 e8 f6 ff fd ff   CALL   function1 
0x1091000a e8 11 00 fe ff   CALL   function2 
0x1091000f 31 c0     XOR   EAX, EAX 
0x10910011 5f      POP   EDI 
0x10910012 5e      POP   ESI 
0x10910013 89 ec     MOV   ESP, EBP 
value = 0 = 0x0 
-> function3 
mock function1 called 
mock function2 called 
value = 0 = 0x0 
-> 

이 방법을 사용하려면 호출 된 함수와 호출하는 함수를 같은 개체로 컴파일 할 수 없습니다. 호출 할 주소가 기호 표의 주소와 일치하지 않을 수도 있습니다. 이것은 VxSim에서 위의 실행 결과입니다. VxSim 로더는 실제로 기본 운영 체제의 로더를 호출합니다.따라서이 주소는 기호 테이블의 주소와 일치하지 않으며 어셈블리는 WorkBench가 실행중인 기본 Pentium 아키텍처를 반영합니다.

메모리에서 호출 할 주소를 직접 조작하여 함수 호출을 재정의 할 수도 있습니다. 이 메서드는 구현에 의존합니다. 아래에서는 gcc -mlongcall 옵션을 사용하여 PPC 용으로 컴파일 된 소스에 대해 설명합니다. 이것은 VxSim이 아닌 실제 대상에서 실행되었습니다.

-> ld < file1.o 
value = 33538216 = 0x1ffc0a8 = function1 + 0x498 
-> ld < file2.o 
value = 33548336 = 0x1ffe830 = function2 + 0x80 
-> ld < mock.o 
value = 33549600 = 0x1ffed20 = function2 + 0x570 
-> ld < file3.o 
value = 33550744 = 0x1fff198 = function2 + 0x9e8 
-> 
-> lkup "function" 
function1     0x01ffbef8 text  (mock.o) 
function1     0x01ffbc10 text  (file1.o) 
function2     0x01ffbf58 text  (mock.o) 
function2     0x01ffe7b0 text  (file2.o) 
function3     0x01ffe558 text  (file3.o) 
value = 0 = 0x0 
-> 
-> function3 
mock function1 called 
mock function2 called 
value = 0 = 0x0 
-> 
-> l function3 
         function3: 
0x1ffe558 9421ffe8 stwu  r1,-24(r1) 
0x1ffe55c 7c0802a6 mfspr  r0,LR 
0x1ffe560 93a1000c stw   r29,12(r1) 
0x1ffe564 93c10010 stw   r30,16(r1) 
0x1ffe568 93e10014 stw   r31,20(r1) 
0x1ffe56c 9001001c stw   r0,28(r1) 
0x1ffe570 7c3f0b78 or   r31,r1,r1 
0x1ffe574 3d200200 lis   r9,512 
0x1ffe578 3ba9bef8 addi  r29,r9,-16648 
0x1ffe57c 7fa803a6 mtspr  LR,r29 
value = 33547648 = 0x1ffe580 = function3 + 0x28 
-> 
-> *0x1ffe578 
function3 + 0x20 = 0x1ffe578: value = 1000980216 = 0x3ba9bef8 
-> *0x1ffe578 = 0x3ba9bc10 
function3 + 0x20 = 0x1ffe578: value = 1000979472 = 0x3ba9bc10 
-> *0x1ffe578 
function3 + 0x20 = 0x1ffe578: value = 1000979472 = 0x3ba9bc10 
-> 
-> function3 
function1 called 
mock function2 called 
value = 0 = 0x0 
-> 

분명히 메모리에서 포인터를 직접 조작하는 작업은 빠르게 지루해집니다. 또한 메모리 보호 기능을 사용하면 VxSim에로드 된 RTP 또는 개체를 변경할 수 없습니다. (따라서, 실제 하드웨어에서이 코드를 실행 한 이유는 무엇입니까?) 가능성을 언급합니다. 주로 질문의 내용과 가장 잘 어울리는 것 같습니다.

마지막으로, 평범하지 않은 단위 테스트의 경우 작업을 위해 특별히 설계된 도구를 고려할 수 있습니다. "vxworks 유닛 테스트 프레임 워크"에 대한 검색을 시도하십시오. 나는 특정 도구에 대해 깊은 경험이 없다. (그리고 스팸을 만나고 싶지도 않다.) 아마도 여기 다른 사람이 좋은 제안을 할 수 있습니다.