覆蓋函數調用的最直接方法是使用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
->
當裝載在符號表中已經使用功能的對象,每次通話將被立即解決與表中的那個符號相關聯的最後一個地址。
-> 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
->
雖然l()
有益顯示功能名稱,沒有符號被實際加載到與所述對象存儲器。而是加載與該函數關聯的最後一個地址的調用。因此,加載另一個同名的函數可能會覆蓋以前加載的函數。
-> 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單元測試框架」。我對任何特定工具都沒有深入的經驗(並且不想遇到垃圾郵件)。也許,這裏的其他人可以提供一個很好的建議。