資料下載:http://m.izizhuan.cn/bbs/dpj-236899-1.html
Overlaying Data Memory 覆蓋數(shù)據(jù)內(nèi)存 Data and bit segments marked as OVERLAYABLE may overlap the same physical memory space. By default, the Keil Cx51 Compiler and the Intel PL/M-51 Compiler store program arguments and local variables in fixed, overlayable memory rather than on the hardware stack. There are two reasons for this: 數(shù)據(jù)和標(biāo)記為可覆蓋的位段可能會與相同的物理內(nèi)存空間重疊。默認(rèn)情況下,Keil Cx51編譯器和Intel PL/M-51編譯器將程序參數(shù)和局部變量存儲在固定的可覆蓋內(nèi)存中,而不是在硬件堆棧中。這有兩個(gè)原因: The 8051 hardware stack resides in on-chip DATA memory which is limited to a maximum of 256 bytes. 8051的硬件堆棧駐留在片上數(shù)據(jù)存儲器中,其限制為最多256字節(jié)。 Stack-based addressing on the 8051 is slow and inefficient. 在8051上基于堆棧的尋址既慢又低效。 There are several benefits to overlaying data space rather than using the stack: 與使用堆棧相比,覆蓋數(shù)據(jù)空間有幾個(gè)好處: - The linker can maximize the available space by overlaying memory.
§ 鏈接器可以通過覆蓋內(nèi)存來最大化可用空間。 - Direct access to memory is much faster on the 8051 than indirect access.
§ 在8051上直接訪問內(nèi)存比間接訪問快得多。 To accomplish overlaying, the linker analyzes all references (calls) between the various functions in the program. Using this information the linker determinesprecisely which data and bit segments may be overlaid. 為了實(shí)現(xiàn)覆蓋,鏈接器分析程序中各個(gè)函數(shù)之間的所有引用 (調(diào)用)。鏈接器使用這些信息精確地確定哪些數(shù)據(jù)和位段可以覆蓋。 The following table describes all BL51 Linker/Locator directives that affect data overlaying. 下表描述了所有影響數(shù)據(jù)覆蓋的BL51鏈接器/定位器指令。 Directive | | | Disables data segment overlaying 禁用數(shù)據(jù)段覆蓋 | | Modifies the call tree for overlaying of local bit and segments 修改調(diào)用樹以覆蓋本地位和段 |
Theory of Operation 操作理論
The system the linker uses to determine which function arguments (or parameters) and variables may be overlaid is quite sophisticated. It begins when the compiler generates the object code for a function. 鏈接器用于確定哪些函數(shù)參數(shù) (或參數(shù)) 和變量可以覆蓋的系統(tǒng)的非常復(fù)雜。它從編譯器為函數(shù)生成目標(biāo)代碼開始。 The compiler stores all function parameters and local variables in overlayable bit, data, pdata, or xdata segments. The segment names generated by the compiler for Parameters and Local Variables are well-defined. They are used by the compiler to access parameters and local variables. 編譯器將所有函數(shù)參數(shù)和局部變量存儲在可覆蓋的位、數(shù)據(jù)、pdata或擴(kuò)展數(shù)據(jù)段中。編譯器為參數(shù)和局部變量生成的段名稱是明確定義的。它們被編譯器用來訪問參數(shù)和局部變量。 As the linker resolves references between functions, it builds a call tree based on where those references appear. For instance, if function_a calls function_b, the compiler inserts a reference to function_b in the object code generated for function_a. When the linker resolves this reference, it inserts the address of function_b and adds a call from function_a to function_b in the call tree. 當(dāng)鏈接器解析函數(shù)之間的引用時(shí),它會根據(jù)這些引用出現(xiàn)的位置構(gòu)建一個(gè)調(diào)用樹。例如,如果function_a調(diào)用function_b,編譯器會在為function_a生成的對象代碼中插入對function_b的引用。當(dāng)鏈接器解析此引用時(shí),它會插入function_b的地址,并在調(diào)用樹中添加從function_a到function_b的調(diào)用。 The local variables and parameters of function_a are overlaid with the variables and parameters of function_b only under the following conditions: function_a的局部變量和參數(shù)僅在以下條件下與function_b的變量和參數(shù)覆蓋: No call references of any kind may exist between function_a and function_b. This includes direct calls between A and B as well as calls from other functions on the A branch to B and calls from functions on the B branch to A. function_a和function_b之間不可存在任何類型的調(diào)用引用。這包括A和B之間的直接調(diào)用,以及從A分支上的其他函數(shù)到B的調(diào)用,以及從B分支上的函數(shù)到A的調(diào)用。 The functions A and B may be invoked by only one program event or root: either the main root or an interrupt but not both. It is impossible to overlay variables and parameters if a function is called by an interrupt and the main program or by two interrupts. 函數(shù)A和B只能被一個(gè)程序事件或根調(diào)用: 主根或中斷,但不能同時(shí)被調(diào)用。如果函數(shù)被中斷和主程序或兩個(gè)中斷調(diào)用,則無法覆蓋變量和參數(shù)。 The segment definitions of functions A and B must conform to the rules for segment names described in the compiler manual. 函數(shù)A和B的段定義必須符合編譯器手冊中描述的段名稱規(guī)則。 The Call Tree 調(diào)用樹 The arguments and local variables of func_a, func_b, and func_c meet the rules listed in the Theory of Operation and, therefore, may be overlaid. The source code for this flowchart is as follows: func_a、func_b和func_c的參數(shù)和局部變量符合操作理論中列出的規(guī)則,因此可以被覆蓋。此流程圖的源代碼如下: - char func_a (char arg1, char arg2, char arg3)
- {
- return (arg1+arg2+arg3);
- }
- int func_b (int arg1, int arg2, int arg3)
- {
- return (arg1+arg2+arg3);
- }
- long func_c (long arg1, long arg2, long arg3)
- {
- return (arg1+arg2+arg3);
- }
- void main (void)
- {
- char var_a;
- int var_b;
- long var_c;
- var_a = func_a(1,2,3);
- var_b = func_b(1,2,3);
- var_c = func_c(1,2,3);
- while (1);
- }
復(fù)制代碼 When the program is linked, the linker generates a call tree which it outputs to the map file.當(dāng)程序鏈接時(shí),鏈接器生成一個(gè)調(diào)用樹,并將其輸出到映射文件。
FUNCTION/MODULE BIT_GROUP DATA_GROUP--> CALLED FUNCTION/MODULE START STOP START STOP====================================================?C_C51STARTUP ----- ----- ----- ----- +--> ?PR?MAIN?MAIN MAIN/MAIN ----- ----- 0008H 000EH +--> ?PR?FUNC_A?MAIN +--> ?PR?FUNC_B?MAIN +--> ?PR?FUNC_C?MAIN FUNC_A/MAIN ----- ----- 000FH 0011H FUNC_B/MAIN ----- ----- 000FH 0014H FUNC_C/MAIN ----- ----- 000FH 001AH
Based on the call tree, the linker reserves the memory used by the functions' arguments and local variables. The linker creates several special Overlay Groups (BIT_GROUP, DATA_GROUP, and so on) that contain the overlaid segments. 基于調(diào)用樹,鏈接器保留函數(shù)參數(shù)和局部變量使用的內(nèi)存。鏈接器會創(chuàng)建多個(gè)包含覆蓋段的特殊覆蓋組 (BIT_GROUP、DATA_GROUP等)。
As you can see from the call tree above, the DATA_GROUP for func_a, func_b, and func_c starts at 000Fh. This shows that the linker believes the arguments and variables for these functions may be safely overlaid. Refer to the memory map for the memory range used by the _DATA_GROUP_. 從上面的調(diào)用樹中可以看到,func_a、func_b和func_c的數(shù)據(jù)組從000Fh開始。這表明鏈接器認(rèn)為這些函數(shù)的參數(shù)和變量可以安全地覆蓋。請參考內(nèi)存映射以了解_DATA_GROUP_使用的內(nèi)存范圍。
START STOP LENGTH ALIGN RELOC MEMORY CLASS SEGMENT NAME========================================================================= * * * * * * * * * * * D A T A M E M O R Y * * * * * * * * * * * * *000000H 000007H 000008H --- AT.. DATA "REG BANK 0"000008H 00001AH 000013H BYTE UNIT DATA _DATA_GROUP_00001BH 00001BH 000001H BYTE UNIT IDATA ?STACK
Note - The linker generates overlay information that is accurate. However, in some instances the default analysis of the call tree is ineffective or incorrect. This occurs with functions that are called by both the main program and an interrupt and with functions called through function pointers.
-鏈接器生成準(zhǔn)確的覆蓋信息。但是,在某些情況下,調(diào)用樹的默認(rèn)分析無效或不正確。這發(fā)生在由主程序和中斷調(diào)用的函數(shù)以及通過函數(shù)指針調(diào)用的函數(shù)中。 - Functions that are called by the main program root and by an interrupt service routine or functions that are called by two or more interrupts may not be overlaid.
被主程序根和中斷服務(wù)例程調(diào)用的函數(shù),或者被兩個(gè)或多個(gè)中斷調(diào)用的函數(shù)不能被覆蓋。 - Functions called through pointers require special handling within the linker in order for overlaying to work properly. This topic is discussed in Function Pointers.
通過指針調(diào)用的函數(shù)需要在鏈接器中進(jìn)行特殊處理,以使覆蓋正常工作。這個(gè)主題在函數(shù)指針中討論。 Overlay Groups覆蓋組When performing overlay analysis, the linker creates groups of segments that are overlaid. The group name indicates the memory type of the variables that it includes. 執(zhí)行疊加分析時(shí),鏈接器會創(chuàng)建疊加的線段組。組名稱指示其包含的變量的內(nèi)存類型。 Group Name | | | | | | | Variables and arguments of type bit. | | | | Variables and arguments other than bit. | | | | Variables and arguments other than bit. | | | | Variables and arguments other than bit. |
When the linker overlays function data memory and creates a group, that groups appears in the linker map file's memory map section. 當(dāng)鏈接器覆蓋函數(shù)數(shù)據(jù)內(nèi)存并創(chuàng)建一個(gè)組時(shí),該組將出現(xiàn)在鏈接器映射文件的內(nèi)存映射部分中。 START STOP LENGTH ALIGN RELOC MEMORY CLASS SEGMENT NAME ========================================================================= * * * * * * * * * * * D A T A M E M O R Y * * * * * * * * * * * * * 000000H 000007H 000008H --- AT.. DATA "REG BANK 0" 000008H 00001AH 000013H BYTE UNIT DATA _DATA_GROUP_ 00001BH 00001BH 000001H BYTE UNIT IDATA ?STACK Groups are created based on the memory model of the function (which specifies the memory class where parameters and variables are stored) and on any variables defined with a specific memory space. 組是基于函數(shù)的內(nèi)存模型 (指定存儲參數(shù)和變量的內(nèi)存類) 以及用特定內(nèi)存空間定義的任何變量創(chuàng)建的.
Disabling Overlay Analysis禁用疊加分析 If you are in doubt about whether certain segments should be overlaid or not, you may disable overlaying of those segments. Segment overlaying may be disabled by the compiler, assembler, or linker. 如果您對某些段是否應(yīng)覆蓋有疑問,可以禁用這些段的覆蓋。段覆蓋可以被編譯器、匯編器或鏈接器禁用。
To disable overlaying in the compiler... 在編譯器中禁用覆蓋... - When the compiler optimization level is set to 1 (using the OPTIMIZE compiler directive) the compiler does not use the OVERLAYABLE relocation type. Local data segments are not overlaid.
- 當(dāng)編譯器優(yōu)化級別設(shè)置為1 (使用optize編譯器指令) 時(shí),編譯器不使用可覆蓋的重定位類型。本地?cái)?shù)據(jù)段不被覆蓋。
To disable overlaying in the assembler... 在匯編器中禁用疊加... n The assembler only creates overlayable segments when the OVERLAYABLE relocation type is specified in a SEGMENT definition. Remove all OVERLAYABLE relocation types from SEGMENT definitions to avoid overlaying data segments. n 導(dǎo)致匯編器僅在段定義中指定覆蓋重定位類型時(shí)才創(chuàng)建覆蓋段。從段定義中刪除所有可覆蓋的重定位類型,以避免覆蓋數(shù)據(jù)段。 To disable overlaying in the linker... 在鏈接器中禁用覆蓋... n The NOOVERLAY linker directive disables all data overlaying for the entire program. n Noverlay鏈接器指令禁用整個(gè)程序的所有數(shù)據(jù)覆蓋。 n The OVERLAY linker directive enables you to manipulate the call tree generated by the linker. For example, OVERLAY (sfname ! *) disables data overlaying for the function specified by sfname. n 使用OVERLAY鏈接器指令,您可以操作由鏈接器生成的調(diào)用樹。例如,覆蓋 (sfname ! *) 將禁用sfname指定的函數(shù)的數(shù)據(jù)覆蓋。
Manipulating the Call Tree操作調(diào)用樹 In most cases, the call tree analysis (or overlay analysis) performed by the linker works correctly and requires no adjustments. However, in some instances the overlay algorithm cannot determine the true structure of the program and the call tree must be adjusted manually using the linker's OVERLAY directive. 在大多數(shù)情況下,鏈接器執(zhí)行的調(diào)用樹分析 (或疊加分析) 可以正常工作,不需要進(jìn)行任何調(diào)整。然而,在某些情況下,覆蓋算法無法確定程序的真正結(jié)構(gòu),并且必須使用鏈接器的覆蓋指令手動調(diào)整調(diào)用樹。 The OVERLAY directive allows you to change the call references used by the linker during the overlay analysis. Using the OVERLAY directive is easy when you know the structure of your program. The program structure or call tree is reflected in the segments listed in the OVERLAY MAP section of the linker map file. OVERLAY指令允許您更改鏈接器在覆蓋分析期間使用的調(diào)用引用。當(dāng)您知道程序的結(jié)構(gòu)時(shí),使用覆蓋指令很容易。程序結(jié)構(gòu)或調(diào)用樹反映在鏈接器映射文件的覆蓋圖部分列出的段中。 In general you must modify the call tree (using the OVERLAY directive) when: 通常,您必須在以下情況下修改調(diào)用樹 (使用覆蓋指令): n A pointer to a function is stored in a variable, table, or array. n 指向函數(shù)的指針存儲在變量、表或數(shù)組中。 n The address of a function is passed or returned as function argument. n 函數(shù)的地址作為函數(shù)參數(shù)傳遞或返回。 n Your program includes a real-time operating system other than RTX51 or RTX51 Tiny. n 你的程序包括除了RTX51或RTX51之外的實(shí)時(shí)操作系統(tǒng)。 Note - The BL51 Linker correctly recognizes the program structure and the call tree of applications using the RTX51 and RTX51-Tiny Real-Time Kernels and automatically create a new root for each task.
- BL51鏈接器使用RTX51和RTX51-Tiny實(shí)時(shí)內(nèi)核正確識別程序結(jié)構(gòu)和應(yīng)用程序的調(diào)用樹,并為每個(gè)任務(wù)自動創(chuàng)建一個(gè)新根。
Function Pointers函數(shù)指針 Function pointers (and indirectly-called functions) present some special issues that must be taken into consideration when creating functions that are called indirectly. 函數(shù)指針 (和間接稱為函數(shù)) 提出了一些特殊問題,在創(chuàng)建間接調(diào)用的函數(shù)時(shí)必須考慮這些問題。 n Function Parameters may be passed only in registers to indirectly-called functions. The typical parameter passing scheme which overlays function parameters and variables may not be used because the compiler does not necessarily know the name of the function called through the pointer. n 導(dǎo)致函數(shù)參數(shù)只能在寄存器中傳遞給間接調(diào)用的函數(shù)。可能不會使用覆蓋函數(shù)參數(shù)和變量的典型參數(shù)傳遞方案,因?yàn)榫幾g器不一定知道通過指針調(diào)用的函數(shù)的名稱。 By default, the Cx51 Compiler passes up to three (3) arguments in registers. Do not assume that just any three arguments fit into registers. Refer to Parameters and Registers in the C51/CX51 User's Guide for more information. 默認(rèn)情況下,Cx51編譯器在寄存器中傳遞最多三個(gè)參數(shù)。不要假設(shè)任意三個(gè)參數(shù)都可以放入寄存器中。有關(guān)更多信息,請參考C51/CX51用戶指南中的參數(shù)和寄存器。 If you require more parameters than will fit into registers, you must merge them into a structure and pass a pointer to the structure. If that is unacceptable, you may use reentrant functions. 如果您需要的參數(shù)超過寄存器容納的數(shù)量,則必須將它們合并到一個(gè)結(jié)構(gòu)中,并傳遞一個(gè)指向該結(jié)構(gòu)的指針。如果這是不可接受的,您可以使用可重入函數(shù)。 n The Call Tree that is automatically generated by the linker, must be adjusted using the OVERLAY directive to include proper references to indirectly-called functions. 由鏈接器自動生成的調(diào)用樹必須使用OVERLAY指令進(jìn)行調(diào)整,以包括對間接調(diào)用的函數(shù)的正確引用。 Note- If you attempt to pass more than three arguments through a pointer to a function, the compiler generates an error message.
- 如果嘗試通過指向函數(shù)的指針傳遞三個(gè)以上的參數(shù),編譯器將生成錯(cuò)誤消息。
- No warning or error is generated if you neglect to adjust the call tree when function pointers are used.
- 如果在使用函數(shù)指針時(shí)忽略了調(diào)整調(diào)用樹,則不會生成任何警告或錯(cuò)誤。
There are two very good reasons why you must adjust the call tree if you use function pointers. 如果您使用函數(shù)指針,有兩個(gè)很好的理由必須調(diào)整調(diào)用樹。 n The linker uses references to build the call tree. If a function initializes a function pointer variable or passes the address of a function to another function, the linker interprets this as a reference and adds a call to the function into the call tree. Later, when the function is actually called through the function, it will use data space that may be overlaid with a function farther up the branch and cause data corruption. If you pass function pointers as arguments, this could even have the effect of corrupting a function pointer which would likely cause a program crash. n 鏈接器使用引用來構(gòu)建調(diào)用樹。如果函數(shù)初始化函數(shù)指針變量或?qū)⒑瘮?shù)地址傳遞給另一個(gè)函數(shù),鏈接器將其解釋為引用,并將對該函數(shù)的調(diào)用添加到調(diào)用樹中。稍后,當(dāng)通過函數(shù)實(shí)際調(diào)用時(shí),它將使用可能被更遠(yuǎn)處分支上的函數(shù)覆蓋的數(shù)據(jù)空間,并導(dǎo)致數(shù)據(jù)損壞。如果您將函數(shù)指針作為參數(shù)傳遞,這甚至可能會破壞函數(shù)指針,從而可能導(dǎo)致程序崩潰。 n In some cases, it may seem easier to simply disable overlay analysis or to simply remove functions called through pointers from the call tree. However, this leads to wasted memory. If you only remove the function from the call tree, you must keep in mind that functions called by the indirectly-called function may overlay their variables. This may also cause data corruption if it is not properly managed. n 在某些情況下,簡單地禁用覆蓋分析或簡單地從調(diào)用樹中刪除通過指針調(diào)用的函數(shù)似乎更容易。但是,這會導(dǎo)致內(nèi)存浪費(fèi)。如果僅從調(diào)用樹中刪除函數(shù),則必須記住,由間接調(diào)用的函數(shù)可能會覆蓋它們的變量。如果管理不當(dāng),這也可能會導(dǎo)致數(shù)據(jù)損壞。 The easiest solution for indirectly-called functions is to remove them from the call tree. For example: 對于間接調(diào)用的函數(shù),最簡單的解決方案是將它們從調(diào)用樹中刪除。例如: ... OVERLAY (sfname-caller ~ (sfname-callee, sfname-callee)) ... And, then add specific references from the calling functions to the indirectly-called function. For example: 然后將調(diào)用函數(shù)的特定引用添加到間接調(diào)用的函數(shù)中。例如: ... OVERLAY (sfname-caller ! (sfname-callee, sfname-callee)) ... As an Argument作為一個(gè)參數(shù) When a function pointer is used as an argument to a function, the call tree generated by the linker is inaccurate. For example, given the following example program: 當(dāng)函數(shù)指針被用作函數(shù)的參數(shù)時(shí),鏈接器生成的調(diào)用樹是不準(zhǔn)確的。例如,給出以下示例程序: int direct_func (int a, int b, int c) { volatile int total = a+b+c; return (total); } int indirect_func (int a, int b, int c) { volatile int total = a+b+c; return (total); } int caller (int (*fp) (int, int, int)) { int retval; retval = direct_func(4,5,6); retval += (*fp) (1,2,3); return (retval); } void main (void) { int value; value = caller(indirect_func); while (1); } The correct Call Tree is illustrated by the following flow chart. 下面的流程圖說明了正確的調(diào)用樹。 However, since indirect_func is referenced in the main function and not in the caller function, the linker generates the following Call Tree and Overlay Map. 但是,由于indirect_func在主函數(shù)中引用,而不是在調(diào)用函數(shù)中引用,鏈接器會生成以下調(diào)用樹和覆蓋圖。 FUNCTION/MODULE BIT_GROUP DATA_GROUP --> CALLED FUNCTION/MODULE START STOP START STOP ============================================================= ?C_C51STARTUP ----- ----- ----- ----- +--> ?PR?MAIN?MAIN MAIN/MAIN ----- ----- 0008H 0009H +--> ?PR?_INDIRECT_FUNC?MAIN +--> ?PR?_CALLER?MAIN _INDIRECT_FUNC/MAIN ----- ----- 000AH 000BH _CALLER/MAIN ----- ----- 000AH 000EH +--> ?PR?_DIRECT_FUNC?MAIN _DIRECT_FUNC/MAIN ----- ----- 000FH 0010H
The linker call tree must be adjusted by removing the reference from main to indirect_func and adding a reference from caller to indirect_func using the following overlay command: 鏈接器調(diào)用樹必須通過使用以下覆蓋命令刪除從main到indirect_func的引用并添加從調(diào)用者到indirect_func的引用來進(jìn)行調(diào)整:
... OVERLAY(main ~ indirect_func, caller ! indirect_func) ...
After adjusting the call tree, the Overlay Map appears as follows: 調(diào)整呼叫樹后,覆蓋圖顯示如下: FUNCTION/MODULE BIT_GROUP DATA_GROUP --> CALLED FUNCTION/MODULE START STOP START STOP ============================================================= ?C_C51STARTUP ----- ----- ----- ----- +--> ?PR?MAIN?MAIN MAIN/MAIN ----- ----- 0008H 0009H +--> ?PR?_CALLER?MAIN _CALLER/MAIN ----- ----- 000AH 000EH +--> ?PR?_DIRECT_FUNC?MAIN +--> ?PR?_INDIRECT_FUNC?MAIN _DIRECT_FUNC/MAIN ----- ----- 000FH 0010H _INDIRECT_FUNC/MAIN ----- ----- 000FH 0010H
In a Local Variable在局部變量中 When a function address is assigned to a local variable (a function pointer), a reference is created in the function where the assignment occurs. If that function also uses the pointer to invoke the function assigned to it, the call tree generated by the linker is accurate. 當(dāng)將函數(shù)地址分配給局部變量 (函數(shù)指針) 時(shí),在進(jìn)行賦值的函數(shù)中創(chuàng)建引用。如果該函數(shù)也使用指針來調(diào)用分配給它的函數(shù),則鏈接器生成的調(diào)用樹是準(zhǔn)確的。 If the function address assigned to the pointer is used in another function (either by returning it or by passing it as an argument),the call tree generated by the linker is inaccurate. For example, given the following example program: 如果分配給指針的函數(shù)地址在另一個(gè)函數(shù)中使用 (通過返回或?qū)⑵渥鳛閰?shù)傳遞),鏈接器生成的調(diào)用樹是不準(zhǔn)確的。例如,給出以下示例程序: int direct_func (int a, int b, int c) { volatile int total = a+b+c; return (total); } int indirect_func (int a, int b, int c) { volatile int total = a+b+c; return (total); } int caller (int (*fp2) (int, int, int)) { int retval; retval = direct_func(4,5,6); retval += (*fp2) (1,2,3); return (retval); } void main (void) { int value; int (*fp) (int, int, int) = indirect_func; value = caller(fp); while (1); }
The correct Call Tree is illustrated by the following flow chart. 下面的流程圖說明了正確的調(diào)用樹。 However, since indirect_func is referenced in the main function and not in the caller function, the linker generates the following Call Tree and Overlay Map. 但是,由于indirect_func在主函數(shù)中引用,而不是在調(diào)用函數(shù)中引用,鏈接器會生成以下調(diào)用樹和覆蓋圖。 FUNCTION/MODULE BIT_GROUP DATA_GROUP --> CALLED FUNCTION/MODULE START STOP START STOP ============================================================= ?C_C51STARTUP ----- ----- ----- ----- +--> ?PR?MAIN?MAIN MAIN/MAIN ----- ----- 0008H 0009H +--> ?PR?_INDIRECT_FUNC?MAIN +--> ?PR?_CALLER?MAIN _INDIRECT_FUNC/MAIN ----- ----- 000AH 000BH _CALLER/MAIN ----- ----- 000AH 000EH +--> ?PR?_DIRECT_FUNC?MAIN _DIRECT_FUNC/MAIN ----- ----- 000FH 0010H The linker call tree must be adjusted by removing the reference from main to indirect_func and adding a reference from caller to indirect_func using the following overlay command: 鏈接器調(diào)用樹必須通過使用以下覆蓋命令刪除從main到indirect_func的引用并添加從調(diào)用者到indirect_func的引用來進(jìn)行調(diào)整: ... OVERLAY(main ~ indirect_func, caller ! indirect_func) ... After adjusting the call tree, the Overlay Map appears as follows: 調(diào)整呼叫樹后,覆蓋圖顯示如下: FUNCTION/MODULE BIT_GROUP DATA_GROUP --> CALLED FUNCTION/MODULE START STOP START STOP ============================================================= ?C_C51STARTUP ----- ----- ----- ----- +--> ?PR?MAIN?MAIN MAIN/MAIN ----- ----- 0008H 0009H +--> ?PR?_CALLER?MAIN _CALLER/MAIN ----- ----- 000AH 000EH +--> ?PR?_DIRECT_FUNC?MAIN +--> ?PR?_INDIRECT_FUNC?MAIN _DIRECT_FUNC/MAIN ----- ----- 000FH 0010H _INDIRECT_FUNC/MAIN ----- ----- 000FH 0010H
In a RAM Variable 在內(nèi)存變量中 When a function pointer is assigned to a global variable that is stored in RAM (DATA, IDATA, PDATA, or XDATA), the call tree generated by the linker is inaccurate. For example, given the following example program: 當(dāng)函數(shù)指針被分配給存儲在內(nèi)存中的全局變量 (DATA、IDATA、PDATA或XDATA) 時(shí),鏈接器生成的調(diào)用樹是不準(zhǔn)確的。例如,給出以下示例程序:
int direct_func (int a, int b, int c) { volatile int total = a+b+c; return (total); } int indirect_func (int a, int b, int c) { volatile int total = a+b+c; return (total); } int (*fp) (int, int, int) = indirect_func; int caller (void) { int retval; retval = direct_func(4,5,6); retval += (*fp) (1,2,3); return (retval); } void main (void) { int value; value = caller(); while (1); }
The correct Call Tree is illustrated by the following flow chart. 下面的流程圖說明了正確的調(diào)用樹。 However, indirect_func is referenced only by the initialization code (initseg) that assigns values to variables (fp, the function pointer, in this case). It is not referenced in the caller function. Therefore, the linker generates the following Call Tree and Overlay Map. 然而,indirect_func僅由為變量賦值的初始化代碼 (initseg) 引用 (在本例中為函數(shù)指針fp)。它沒有在調(diào)用函數(shù)中引用。因此,鏈接器生成以下調(diào)用樹和覆蓋圖。
FUNCTION/MODULE BIT_GROUP DATA_GROUP --> CALLED FUNCTION/MODULE START STOP START STOP ============================================================= ?C_C51STARTUP ----- ----- ----- ----- +--> ?PR?MAIN?MAIN +--> ?C_INITSEG MAIN/MAIN ----- ----- 0008H 0009H +--> ?PR?CALLER?MAIN CALLER/MAIN ----- ----- 000AH 000BH +--> ?PR?_DIRECT_FUNC?MAIN _DIRECT_FUNC/MAIN ----- ----- 000CH 000DH ?C_INITSEG ----- ----- ----- ----- +--> ?PR?_INDIRECT_FUNC?MAIN _INDIRECT_FUNC/MAIN ----- ----- 0008H 0009H
The linker call tree must be adjusted by removing the reference from initseg to indirect_func and adding a reference from caller to indirect_func using the following overlay command: 必須通過使用以下覆蓋命令刪除從initseg到indirect_func的引用并添加從調(diào)用者到indirect_func的引用來調(diào)整鏈接器調(diào)用樹: ... OVERLAY(?C_INITSEG ~ indirect_func, caller ! indirect_func) ... After adjusting the call tree, the Overlay Map appears as follows: 調(diào)整調(diào)用樹后,覆蓋圖顯示如下: FUNCTION/MODULE BIT_GROUP DATA_GROUP --> CALLED FUNCTION/MODULE START STOP START STOP ============================================================= ?C_C51STARTUP ----- ----- ----- ----- +--> ?PR?MAIN?MAIN +--> ?C_INITSEG MAIN/MAIN ----- ----- 0008H 0009H +--> ?PR?CALLER?MAIN CALLER/MAIN ----- ----- 000AH 000BH +--> ?PR?_DIRECT_FUNC?MAIN +--> ?PR?_INDIRECT_FUNC?MAIN _DIRECT_FUNC/MAIN ----- ----- 000CH 000DH _INDIRECT_FUNC/MAIN ----- ----- 000CH 000DH ?C_INITSEG ----- ----- ----- -----
Note - Since the fp variable is assigned its value in its definition, the initialization references the indirect_func function. However, if fp was initialized by code in the main function, there would be a reference from the main function to the indirect_func function.
- 由于fp變量在其定義中被分配了其值,因此初始化引用了indirect_func函數(shù)。但是,如果fp通過主函數(shù)中的代碼初始化,則主函數(shù)將引用indirect_func函數(shù)。
- In this example, there is a reference from the initialization code to indirect_func only because the fp variable is actually initialized. This is going to be the case with all function pointers stored in RAM. If the memory type of fp is changed to code (so that the pointer is stored in ROM), there would be no reference from the initialization code. Instead, there would be a reference from the code segment of the source file (?CO?filename). There are subtle differences to note when a function pointer is stored In a ROM Variable.
- 在這個(gè)示例中,初始化代碼中僅引用了indirect_func,因?yàn)?/font>fp變量實(shí)際上已初始化。這將是所有存儲在內(nèi)存中的函數(shù)指針的情況。如果fp的內(nèi)存類型更改為代碼 (以便將指針存儲在ROM中),則初始化代碼將沒有引用。相反,將會有一個(gè)來自源文件代碼段的引用 (文件名)。當(dāng)函數(shù)指針存儲在ROM變量中時(shí),需要注意細(xì)微的區(qū)別。
In a ROM Variable 在ROM變量中 When a function pointer is assigned to a global variable that is stored in ROM (CODE), the call tree generated by the linker may be completely accurate. For example, given the following example program: 當(dāng)一個(gè)函數(shù)指針被分配給一個(gè)存儲在ROM (CODE) 中的全局變量時(shí),鏈接器生成的調(diào)用樹可能是完全準(zhǔn)確的。例如,給出以下示例程序: int direct_func (int a, int b, int c) { volatile int total = a+b+c; return (total); } int indirect_func (int a, int b, int c) { volatile int total = a+b+c; return (total); } int (* code fp) (int, int, int) = indirect_func; int caller (void) { int retval; retval = direct_func(4,5,6); retval += (*fp) (1,2,3); return (retval); } void main (void) { int value; value = caller(); while (1); } The correct Call Tree is illustrated by the following flow chart. 下面的流程圖說明了正確的調(diào)用樹。 However, indirect_func is referenced by the code segment of the main source file (?co?main) that contains the function pointer fp. It is not referenced in thecaller function. However, the caller function does reference the fp variable. Therefore, the linker generates the following Call Tree and Overlay Map. 但是,indirect_func由包含函數(shù)指針fp的主源文件 (?co?main) 的代碼段引用。它沒有在調(diào)用函數(shù)中引用。但是,調(diào)用函數(shù)確實(shí)引用了fp變量。因此,鏈接器生成以下調(diào)用樹和覆蓋圖。 FUNCTION/MODULE BIT_GROUP DATA_GROUP --> CALLED FUNCTION/MODULE START STOP START STOP ============================================================= ?C_C51STARTUP ----- ----- ----- ----- +--> ?PR?MAIN?MAIN MAIN/MAIN ----- ----- 0008H 0009H +--> ?PR?CALLER?MAIN CALLER/MAIN ----- ----- 000AH 000BH +--> ?PR?_DIRECT_FUNC?MAIN +--> ?CO?MAIN _DIRECT_FUNC/MAIN ----- ----- 000CH 000DH ?CO?MAIN ----- ----- ----- ----- +--> ?PR?_INDIRECT_FUNC?MAIN _INDIRECT_FUNC/MAIN ----- ----- 000CH 000DH
The ?CO?MAIN segment contains all code variables declared in the MAIN.C file. If this consists of only function pointers, all of which are accessed by a C function, then no changes to the call tree are required. Refer to the following rules regarding global function pointers stored in CODE to determine if adjustments to the call tree are required. 這個(gè)?CO?MAIN段包含在MAIN.C文件中聲明的所有代碼變量。如果這僅由函數(shù)指針組成,所有這些指針都由C函數(shù)訪問,則不需要更改調(diào)用樹。請參考以下有關(guān)存儲在代碼中的全局函數(shù)指針的規(guī)則,以確定是否需要調(diào)整調(diào)用樹。 n Global function pointers assigned to CODE memory may be the only variables declared in a source file. n 分配給代碼內(nèi)存的全局函數(shù)指針可能是源文件中聲明的唯一變量。 n Function pointers declared must all be used (or have the potential to be used) in the function or functions that reference them. n 聲明的函數(shù)指針必須全部在引用它們的函數(shù)中使用 (或有可能使用)。 n If some, but not all, function pointers are used in a function, you must manually adjust the call tree to reflect this relationship. Otherwise, precious memory is wasted by the inaccurate call tree. n 如果在函數(shù)中使用了一些函數(shù)指針,但不是全部,則必須手動調(diào)整調(diào)用樹以反映此關(guān)系。否則,寶貴的內(nèi)存會被不準(zhǔn)確的調(diào)用樹浪費(fèi)掉。 Note - The fp variable is located in CODE memory which is stored in the ?CO?MAIN segment — along with all other global CODE variables declared in MAIN.C.
- fp變量位于代碼存儲器中,代碼存儲器存儲在?CO?主段-以及在MAIN.C中聲明的所有其他全局代碼變量。
- References to any global CODE variable in the MAIN.C source file (even from another source file) is indicated in the call tree by a reference to the ?CO?MAIN segment.
- 對MAI N.C源文件 (甚至來自另一個(gè)源文件) 中任何全局代碼變量的引用在調(diào)用樹中都通過對?的引用來指示CO?主要部分。
Summary *** Warning L12 No Reference Between Segments
Segment 1: segment-name
Segment 2: segment-name Description The linker encountered an error deleting references between segments that have no references. 鏈接器在刪除沒有引用的段之間的引用時(shí)遇到錯(cuò)誤
Cause This message is caused when the OVERLAY directive is used to delete a reference between two segments that do not reference each other. 當(dāng)使用OVERLAY指令刪除不相互引用的兩個(gè)段之間的引用時(shí),會導(dǎo)致此消息。
Resolution Remove the OVERLAY parameter that attempts to delete the reference between the specified segments. 移除嘗試刪除指定段之間參考的OVERLAY參數(shù)。 |