æ‘˜è¦ è»Ÿä»¶æ¸¬è©¦ä¸ï¼Œè¦†è“‹ã€æ•…éšœæ³¨å…¥ã€æ€§èƒ½åˆ†æžç‰å»£æ³›ä½¿ç”¨çš„動態測試方法å‡åŸºäºŽç¨‹åºæ’è£æŠ€è¡“ã€‚æœ¬æ–‡ä»‹ç´¹ä¸€ç¨®é€šéŽåˆ†æžå’Œä¿®æ”¹GCCç·¨è¯å·¥å…·ï¼Œå¯¦ç¾ç¨‹åºæ’è£çš„æ–°æ–¹æ³•。該方法具有批é‡è‡ªå‹•æ’è£ï¼Œæ’è£èˆ‡ç·¨è¯é€£æŽ¥ç·Šå¯†çµåˆï¼Œé©ç”¨èªžè¨€å»£æ³›ç‰å„ªé»žã€‚最åŽå…·é«”討論了如何在ARM嵌入å¼ç¨‹åºä¸å¯¦ç¾ç¨‹åºæ’è£ï¼Œå¹¶çµ¦å‡ºä¿®æ”¹GCCçš„æºä»£ç¢¼ã€‚
é—œéµè©ž GCC ç¨‹åºæ’è£ ARM嵌入å¼ç¨‹åº
引 言
ç¨‹åºæ’è£ï¼ˆProgram Instrumentation)概念最先是由J.G.Huang教授æå‡ºï¼Œæ˜¯å€ŸåŠ©å¾€è¢«æ¸¬ç¨‹åºä¸æ’å…¥æ“作(稱為“探é‡â€ï¼‰ï¼Œä»¥ä¾¿ç²å–程åºçš„æŽ§åˆ¶æµå’Œæ•¸æ“šæµä¿¡æ¯ï¼Œå¾žè€Œå¯¦ç¾æ¸¬è©¦ç›®çš„的方法。在軟件動態測試ä¸ï¼Œç¨‹åºæ’è£æ˜¯ä¸€ç¨®åŸºæœ¬çš„æ¸¬è©¦æ‰‹æ®µï¼Œæ‡‰ç”¨å»£æ³›ï¼Œæ˜¯è¦†è“‹çŽ‡æ¸¬è©¦ã€è»Ÿä»¶æ•…障注入和動態性能分æžçš„基礎技術。
GCC(GNU Compiler Collection)是一個高度優化,高度å¯ç§»æ¤ï¼Œå»£æ³›ä½¿ç”¨çš„ç·¨è¯ç³»çµ±ã€‚它能處ç†å¤šç¨®èªžè¨€ï¼ŒåŒ…括Cï¼C++ã€Fortranã€Javaå’ŒPascalç‰å¤šç¨®èªžè¨€å‰ç«¯ï¼Œè€Œä¸”åŽç«¯æ”¯æŒå¹¾ä¹Žæ‰€æœ‰çš„處ç†å™¨çµæ§‹ã€‚GCC作為æºç¢¼é–‹æ”¾çš„軟件,人們å¯ä»¥è‡ªç”±ä¿®æ”¹å’Œä½¿ç”¨ï¼›åŠ å…¥æ’è£æ¨¡å¡ŠåŽï¼Œåœ¨GCC所支æŒçš„語言ä¸éƒ½å¯æ’入相應的測試代碼(這里åªä»‹ç´¹C語言的æ’è£æ¨¡å¡Šï¼‰ã€‚本文將詳細敘述如何修改GCCï¼Œä½¿å…¶åœ¨ç·¨è¯æ¯å€‹C函數時,分別將å„個形å¼åƒæ•¸é€£åŒè©²å‡½æ•¸å傳éžçµ¦ä¸€å€‹æŒ‡å®šå‡½æ•¸ã€‚該指定函數的返回值賦予原來的形å¼åƒæ•¸ï¼Œå¾žè€Œå¯ä»¥äººç‚ºæŽ§åˆ¶è¢«æ’è£å‡½æ•¸çš„æ¯å€‹åƒæ•¸å¯¦éš›å€¼ï¼Œé€²è€Œå®Œæˆå„種è¦å‰‡ä¸‹çš„æ¸¬è©¦ã€‚
1 GCCç·¨è¯æµç¨‹åˆ†æž
ç·¨è¯å™¨çš„工作是將æºä»£ç¢¼ï¼ˆé€šå¸¸ä½¿ç”¨é«˜ç´šèªžè¨€ç·¨å¯«ï¼‰ç¿»è¯æˆç›®æ¨™ä»£ç¢¼ï¼ˆé€šå¸¸æ˜¯ä½Žç´šçš„目標代碼或者機器語言)。在ç¾ä»£ç·¨è¯å™¨çš„實ç¾ä¸ï¼Œé€™å€‹å·¥ä½œä¸€èˆ¬æ˜¯åˆ†ç‚ºå…©å€‹éšŽæ®µä¾†å¯¦ç¾çš„:
第一階段,編è¯å™¨çš„å‰ç«¯æŽ¥æ”¶è¼¸å…¥çš„æºä»£ç¢¼ï¼Œç¶“éŽè©žæ³•ã€èªžæ³•和語義分æžç‰å¾—到æºç¨‹åºçš„æŸç¨®ä¸é–“表示方å¼ã€‚
第二階段,編è¯å™¨çš„åŽç«¯å°‡å‰ç«¯è™•ç†ç”Ÿæˆçš„ä¸é–“表示方å¼é€²è¡Œä¸€äº›å„ªåŒ–,并最終生æˆåœ¨ç›®æ¨™æ©Ÿå™¨ä¸Šå¯é‹è¡Œçš„代碼。
GCCç·¨è¯å™¨ä»¥ä¸€å€‹å‡½æ•¸ç‚ºå–®ä½å°ç¶“éŽé 處ç†çš„è¼¸å…¥æºæ–‡ä»¶é€²è¡Œç·¨è¯è™•ç†ã€‚æ ¹æ“šGNU Bison(一個類似YACC但功能更強大的文法分æžå·¥å…·ï¼‰ç”Ÿæˆçš„語法分æžç¨‹åºï¼Œå‰ç«¯å®Œæˆèªžæ³•ã€èªžç¾©åˆ†æžï¼Œå»ºç«‹èªžæ³•æ¨¹ï¼Œå¹¶è½‰æ›æˆä¸é–“代碼。GCC內部使用了一種能å°å¯¦éš›çš„é«”ç³»çµæ§‹åšä¸€ç¨®æŠ½è±¡çš„,與硬件平臺無關的語言,這個ä¸é–“語言就是RTL(Register Ttansfer Language)。通éŽä¿®æ”¹æºç¨‹åºçš„RTL,å¯ä»¥æ”¹è®Šã€åˆªé™¤æºç¨‹åºï¼ŒåŒ…括æ’入所需è¦çš„代碼,由GCCåŽç«¯è™•ç†å¹¶æœ€çµ‚è¼¸å‡ºå°æ‡‰ç¡¬ä»¶å¹³è‡ºçš„匯編碼,æºç¨‹åºç„¡éœ€æ‰‹å·¥ä¿®æ”¹ä¾¿å¯å¯¦ç¾æ’è£åŠŸèƒ½ã€‚
GCC的入å£é»žmain函數在文件main.cä¸ã€‚æ¤å‡½æ•¸éžå¸¸ç°¡å–®ï¼Œåªæœ‰ä¸€æ¢ç›´æŽ¥èª¿ç”¨toplev_main函數的語å¥ã€‚toplev_main函數是在toplev.c文件ä¸å®šç¾©çš„,以下我們åªé—œå¿ƒèˆ‡ç·¨è¯æœ‰é—œçš„æºç¢¼ï¼Œå…¶ä»–çš„æš«æ™‚å¿½ç•¥ã€‚toplev_main䏿œ€é‡è¦çš„æ˜¯èª¿ç”¨äº†do_complile函數,這個函數從åå—看就是åšç·¨è¯å·¥ä½œçš„;而在æ¤ä¹‹åŽï¼Œtoplev_main函數就返回了。dD_compile函數也是在tokv.cä¸å®šç¾©çš„,其ä¸çœŸæ£é€²è¡Œç·¨è¯å·¥ä½œçš„æ˜¯èª¿ç”¨compilte_file函數。compik_file函數最終調用了一個鉤å函數來分æžï¼ˆparse)整個輸入文件:
(*lang_hooks.parse_file)(set_yydebug);
這里的lang_hooks是一個全局變é‡ï¼Œä¸åŒèªžè¨€çš„å‰ç«¯å°æ¤è³¦ä»¥ä¸åŒçš„值。å°C語言來說,這æ¢èªžå¥ç›¸ç•¶äºŽèª¿ç”¨äº†c-opts.cä¸çš„c_common_parse_file函數。c_com-mon_parse_fileä¸èª¿ç”¨äº†c-parse.cä¸çš„c_parse_file函數;在æ¤å‡½æ•¸ä¸åˆèª¿ç”¨äº†åŒæ–‡ä»¶ä¸çš„yyparseå‡½æ•¸ï¼Œè©²å‡½æ•¸è² è²¬è§£æžCèªžè¨€æºæ–‡ä»¶ï¼Œå¹¶è½‰åŒ–ç‚ºç‰¹æ®Šçš„èªžæ³•æ¨¹çµæ§‹ã€‚該函數是GNU bisonå°‡YACC轉變為C語言而自動生æˆçš„,所以這段代碼閱讀起來比較困難,但我們并ä¸é—œå¿ƒèªžæ³•分æžçš„細節。在完æˆå‡½æ•¸é«”的分æžåŽï¼Œåˆ©ç”¨å·²ç¶“建立的treeçµæ§‹ç”ŸæˆRTLï¼Œå„ªåŒ–åŽæœ€çµ‚輸出匯編碼;自æ¤C函數的編è¯å°±ç®—çµæŸäº†ï¼Œé€™äº›æ˜¯ç”±yyparse調用finish_function函數完æˆçš„。finish_functionå‡½æ•¸ä¸æœ€é‡è¦çš„函數是tree_rest_of_compilation(定義在tree_optimize.cä¸ï¼‰ï¼Œå®ƒæ˜¯çœŸæ£å¯¦ç¾ä¸Šè¿°åŠŸèƒ½çš„å‡½æ•¸ã€‚ç‚ºäº†èªªæ˜Žå®ƒæ‰€åšçš„具體事情,我們將該函數åšäº†åˆªæ¸›ï¼Œä¿ç•™äº†é—œéµçš„地方。

將函數å„個部分展開æˆRTLå½¢å¼åŽï¼Œèª¿ç”¨å‡½æ•¸rest_of_compilationå°‡RTL輸出為匯編碼。至æ¤ï¼Œå¾—到了一張清晰的GCCç·¨è¯æ™‚的函數調用路線,如表1所列。
2 基于GCCçš„ç¨‹åºæ’è£æŠ€è¡“
æ ¹æ“šæ’è£æ¸¬è©¦çš„è¦æ±‚,需è¦åœ¨å‡½æ•¸é–‹å§‹æ™‚為æ¯å€‹åƒæ•¸èª¿ç”¨é‰¤å函數,并用鉤åå‡½æ•¸çš„è¿”å›žå€¼æ›´æ–°åƒæ•¸çš„å€¼ï¼›åŒæ™‚,將被æ’è£å‡½æ•¸çš„åç¨±å£“å…¥å‡½æ•¸æœ¬åœ°æ£§å…§ï¼Œä½œç‚ºè©²å‡½æ•¸çš„ä¸€å€‹åŒ¿åæœ¬åœ°è®Šé‡ï¼Œåªç”¨äºŽå‚³éžçµ¦é‰¤å函數。從上é¢åˆ—出的tree_rest_of_compilation函數æºç¢¼å¾—çŸ¥ï¼Œè² è²¬å»ºç«‹è¢«ç·¨è¯å‡½æ•¸åƒæ•¸å’Œè¿”回值的函數是expand_function_start,定義是在文件function.cä¸ã€‚expand_function_startä¸è™•ç†å‡½æ•¸åƒæ•¸å’Œè¿”回值的函數是assign_parms,這是需è¦ç‰¹åˆ¥é—œæ³¨çš„函數。以下是該函數簡化的å½ç¢¼ï¼š

æ–œé«”åŠ ç²—çš„éƒ¨åˆ†æ˜¯å¢žåŠ çš„ä»£ç¢¼ã€‚åœ¨for循環å‰ï¼Œç²å¾—ç•¶å‰ç·¨è¯çš„函數å(見æºç¢¼ä¸â‘ ä½ç½®ï¼‰ï¼›ä½†æš«æ™‚ä¸èƒ½è¼¸å‡ºåˆ°å‡½æ•¸çš„RTLéˆä¸ï¼Œå› 為本地棧è¦åœ¨æ‰€æœ‰åƒæ•¸å‚³éžå®Œç•¢æ‰å®Œå…¨å»ºç«‹èµ·ä¾†ã€‚在forå¾ªç’°é«”çµæŸå‰ï¼Œè¨˜éŒ„ä¸‹å‡½æ•¸åƒæ•¸çš„一份拷è²ï¼ˆè¦‹â‘¡ï¼‰ï¼Œæœ€åŽèª¿ç”¨ã€‚insert_function_name_local函數,將當å‰å‡½æ•¸åæ’å…¥æœ¬åœ°æ£§ï¼Œå¹¶ä¸”ä¿®æ£æ£§æŒ‡é‡ï¼ˆè¦‹â‘¢ï¼‰ã€‚ç¶“éŽä»¥ä¸Šä¿®æ”¹ï¼Œå¾—到了æ’è£æ‰€éœ€çš„æ‰€æœ‰ä¿¡æ¯ï¼ŒåŒ…æ‹¬å‡½æ•¸åƒæ•¸å’Œå‡½æ•¸å稱的RTX表示。GCC將函數編è¯åŽç”Ÿæˆçš„RTX表示以éˆè¡¨å½¢å¼çµ„織,最åŽä¸€æ¬¡æ€§æŠŠé€™å€‹RTXéˆè¡¨è¼¸å‡ºç‚ºåŽç«¯å¹³è‡ºçš„匯編碼。完æˆé€™é …工作的是rest_of_compilation函數,所以在調用rest_of_complilationå‡½æ•¸å‰æ’入我們的RTXï¼Œæœ€çµ‚å®Œæˆæ’è£ï¼Œç”±å‡½æ•¸inject_rtlè² è²¬å®Œæˆã€‚䏋颿˜¯inject_rtl的主è¦ä»£ç¢¼ï¼š
3 APCSèˆ‡ç¨‹åºæ’è£å¯¦ç¾
ç·¨è¯å™¨å¿…é ˆä»¥ä¸€å¥—çµ±ä¸€çš„æ–¹æ³•ç·¨è¯å‡½æ•¸çš„定義和調用éŽç¨‹ï¼Œæ‰èƒ½ç¢ºä¿ä¸åŒèªžè¨€ç·¨å¯«çš„函數能相互調用。è¦å®šé€™äº›ç´°ç¯€çš„便å«ä½œâ€œå‡½æ•¸èª¿ç”¨è¦èŒƒï¼ˆProcedure Call Stand-ard)â€ã€‚ARMé«”ç³»çµæ§‹å®šç¾©äº†è‡ªå·±çš„函數調用è¦èŒƒâ€”—ARM函數調用標準(ARM Procedure Call Standard,APCS)。雖然APCS䏿˜¯å¼·åˆ¶æ€§çš„,但實ç¾APCSå¹¶ä¸å›°é›£ï¼Œè€Œä¸”å¯ç²å¾—統一的二進制兼容的好處,所以大部分的編è¯å™¨éƒ½å¯¦ç¾äº†APCS,其ä¸åŒ…括GCC。
APCSä¸å‡½æ•¸å‚³éžåƒæ•¸çš„定義如下:
â—‡å‰4個整數實åƒï¼ˆæˆ–者更少)被è£è¼‰åˆ°r0~r3。å‰4個整數實åƒï¼ˆæˆ–者更少)被è£è¼‰åˆ°r0~r3。
â—‡å‰4個浮點實åƒï¼ˆæˆ–者更少)被è£è¼‰åˆ°f0~f3。
â—‡å¦‚æžœåƒæ•¸ç‚ºé›™å—(8å—ç¯€ï¼‰ï¼Œå°±å¿…é ˆå¾žå¶æ•¸å¯„å˜å™¨é–‹å§‹æ”¾ç½®ã€‚
â—‡å¦‚æžœä¸€å€‹åƒæ•¸ä¸èƒ½å®Œå…¨æ”¾å…¥å¯„å˜å™¨ä¸ï¼Œå‰‡è¶…éŽçš„那部分拷è²åˆ°æ£§ä¸ã€‚
其他任何實åƒï¼ˆå¦‚果有的話)å˜å„²åœ¨å…§å˜ä¸ï¼Œç”¨é€²å…¥å‡½æ•¸æ™‚緊接在sp值上é¢çš„å—來指å‘。æ›å¥è©±èªªï¼Œå…¶ä½™çš„åƒæ•¸è¢«å£“å…¥æ£§é ‚ã€‚æ‰€ä»¥ï¼Œè¦æƒ³ç°¡å–®ï¼Œæœ€å¥½å®šç¾©æŽ¥å—4å€‹æˆ–æ›´å°‘çš„æ•´æ•¸åƒæ•¸çš„函數。
本文所述的æ’å…¥å‡½æ•¸åªæœ‰å…©å€‹æ•´åž‹å½¢åƒï¼Œæ‰€ä»¥èª¿ç”¨æ™‚åªéœ€å°‡å…©å€‹å¯¦åƒåˆ†åˆ¥å‚³å…¥roå’Œrl。GCCæä¾›emit_li-brary_call函數用來生æˆå‡½æ•¸èª¿ç”¨çš„RTL碼,GCC將按照APCS產生æ£ç¢ºçš„函數調用匯編碼。函數定義在calls.cä¸ï¼ŒåŽŸåž‹ç‚ºï¼š

æ’入所需函數åŽï¼Œéœ€è¦å°‡è¿”å›žå€¼è³¦å€¼çµ¦å°æ‡‰çš„被æ’è£å‡½æ•¸çš„å½¢åƒã€‚以下是æ’入函數insert_parms_test_function的完整代碼:
4 實 例
為便于檢查æ’è£æ•ˆæžœï¼Œç”¨ç¶“éŽä¿®æ”¹çš„GCCç·¨è¯ä¸€æ®µç°¡å–®çš„C語言程åºã€‚該程åºç‚ºä¸€å€‹ç¨ç«‹å‡½æ•¸foo,接å—å…©å€‹æ•´æ•¸é¡žåž‹çš„åƒæ•¸ã€‚具體代碼如下:
從GCC輸出的匯編碼å¯ä»¥çœ‹åˆ°ï¼Œfooå‡½æ•¸çš„å…©å€‹åƒæ•¸éƒ½ç¶“éŽé‰¤å函數pt_hook_partnsçš„è™•ç†æ›´æ–°ï¼›åœ¨pt_hook_parms函數內,å¯ä»¥æ ¹æ“šæ¸¬è©¦ç®—æ³•è¿”å›žä¸åŒçš„邊界值,從而é”到測試的目的。ä¾ç…§æ¤æ–¹æ³•,一個實際程åºç¶“éŽæ’è£åŽï¼Œåœ¨ARMæ¨¡æ“¬å™¨ä¸Šé †åˆ©é‹è¡Œï¼Œå¹¶å–å¾—é æœŸçš„æ¸¬è©¦æ•ˆæžœã€‚
çµèªž
本文詳細地論述了修改GCCå¢žåŠ æ’è£åŠŸèƒ½çš„å¯¦ç¾æ–¹æ³•。按照這樣的æ€è·¯ï¼ŒæˆåŠŸåœ°å¯¦ç¾äº†åŸºäºŽARM7芯片的嵌入å¼ç³»çµ±çš„å‹•æ…‹åƒæ•¸é‚Šç•Œæ¸¬è©¦ï¼Œé”åˆ°äº†é æœŸçš„æ•ˆæžœã€‚本文所述的æ’è£å‡½æ•¸æ¯”較簡單,沒有å€åˆ†åƒæ•¸çš„é¡žåž‹ï¼Œæ‰€æœ‰åƒæ•¸å‡æŒ‰ç…§ä¸€å€‹å—大å°ä¾†è™•ç†ï¼›ä¸‹ä¸€æ¥çš„å·¥ä½œæ˜¯ç´°åˆ†åƒæ•¸ä¸åŒé¡žåž‹ï¼Œæ’è£ä¸åŒçš„處ç†å‡½æ•¸ã€‚作為一種通用的æ’è£æ–¹æ³•ï¼Œåœ¨æ¤æ‘¹ç¤Žä¸Šï¼Žé€šéŽè˜åˆ¥ä¸åŒçš„æ’è£é»žå’Œæ’è£ä¸åŒçš„函數,å¯ä»¥å¯¦ç¾å‡½æ•¸èª¿ç”¨æ£§æª¢æŸ¥ï¼Œç¨‹åºè¦†è“‹çŽ‡æ¸¬è©¦ï¼Œç²å–函數實際執行時間ç‰éœ€è¦æ’è£æŠ€è¡“ä½œç‚ºåŸºç¤Žçš„åŠŸèƒ½ã€‚