找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 529|回复: 0
打印 上一主题 下一主题
收起左侧

KEIL-BL51用户向导之覆盖数据内存 中文翻译

[复制链接]
跳转到指定楼层
楼主
ID:600825 发表于 2025-10-23 22:22 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
资料下载:http://www.51hei.com/bbs/dpj-236899-1.html

Overlaying Data Memory
覆盖数据内存
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:
数据和标记为可覆盖的位段可能会与相同的物理内存空间重叠。默认情况下,Keil Cx51编译器和Intel PL/M-51编译器将程序参数和局部变量存储在固定的可覆盖内存中,而不是在硬件堆栈中。这有两个原因:
   The 8051 hardware stack resides in on-chip DATA memory which is limited to a maximum of 256 bytes.
   8051的硬件堆栈驻留在片上数据存储器中,其限制为最多256字节。
   Stack-based addressing on the 8051 is slow and inefficient.
   在8051上基于堆栈的寻址既慢又低效。
There are several benefits to overlaying data space rather than using the stack:
与使用堆栈相比,覆盖数据空间有几个好处:
  • The linker can maximize the available space by overlaying memory.
§  链接器可以通过覆盖内存来最大化可用空间。
  • Direct access to memory is much faster on the 8051 than indirect access.
§  在8051上直接访问内存比间接访问快得多。
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.
为了实现覆盖,链接器分析程序中各个函数之间的所有引用 (调用)。链接器使用这些信息精确地确定哪些数据和位段可以覆盖。
The following table describes all BL51 Linker/Locator directives that affect data overlaying.
下表描述了所有影响数据覆盖的BL51链接器/定位器指令。
Directive
Description
NOOVERLAY
Disables data segment overlaying
禁用数据段覆盖
OVERLAY
Modifies the call tree for overlaying of local bit and segments
修改调用树以覆盖本地位和段

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.
链接器用于确定哪些函数参数 (或参数) 和变量可以覆盖的系统的非常复杂。它从编译器为函数生成目标代码开始。
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.
编译器将所有函数参数和局部变量存储在可覆盖的位、数据、pdata或扩展数据段中。编译器为参数和局部变量生成的段名称是明确定义的。它们被编译器用来访问参数和局部变量。
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.
当链接器解析函数之间的引用时,它会根据这些引用出现的位置构建一个调用树。例如,如果function_a调用function_b,编译器会在为function_a生成的对象代码中插入对function_b的引用。当链接器解析此引用时,它会插入function_b的地址,并在调用树中添加从function_a到function_b的调用。
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的局部变量和参数仅在以下条件下与function_b的变量和参数覆盖:
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之间不可存在任何类型的调用引用。这包括A和B之间的直接调用,以及从A分支上的其他函数到B的调用,以及从B分支上的函数到A的调用。
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.
函数A和B只能被一个程序事件或根调用: 主根或中断,但不能同时被调用。如果函数被中断和主程序或两个中断调用,则无法覆盖变量和参数。
The segment definitions of functions A and B must conform to the rules for segment names described in the compiler manual.
函数A和B的段定义必须符合编译器手册中描述的段名称规则。
The Call Tree
调用树
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的参数和局部变量符合操作理论中列出的规则,因此可以被覆盖。此流程图的源代码如下:
  1. char func_a (char arg1, char arg2, char arg3)
  2. {
  3.     return (arg1+arg2+arg3);
  4. }
  5. int func_b (int arg1, int arg2, int arg3)
  6. {
  7.     return (arg1+arg2+arg3);
  8. }
  9. long func_c (long arg1, long arg2, long arg3)
  10. {
  11.     return (arg1+arg2+arg3);
  12. }
  13. void main (void)
  14. {
  15. char var_a;
  16. int  var_b;
  17. long var_c;
  18. var_a = func_a(1,2,3);
  19. var_b = func_b(1,2,3);
  20. var_c = func_c(1,2,3);
  21.   while (1);
  22. }
复制代码
When the program is linked, the linker generates a call tree which it outputs to the map file.
当程序链接时,链接器生成一个调用树,并将其输出到映射文件。

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.
基于调用树,链接器保留函数参数和局部变量使用的内存。链接器会创建多个包含覆盖段的特殊覆盖组 (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_.
从上面的调用树中可以看到,func_a、func_b和func_c的数据组从000Fh开始。这表明链接器认为这些函数的参数和变量可以安全地覆盖。请参考内存映射以了解_DATA_GROUP_使用的内存范围。

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.
-链接器生成准确的覆盖信息。但是,在某些情况下,调用树的默认分析无效或不正确。这发生在由主程序和中断调用的函数以及通过函数指针调用的函数中。
  • 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.
被主程序根和中断服务例程调用的函数,或者被两个或多个中断调用的函数不能被覆盖。
  • Functions called through pointers require special handling within the linker in order for overlaying to work properly. This topic is discussed in Function Pointers.
通过指针调用的函数需要在链接器中进行特殊处理,以使覆盖正常工作。这个主题在函数指针中讨论。
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.
执行叠加分析时,链接器会创建叠加的线段组。组名称指示其包含的变量的内存类型。
Group Name
Segment
Prefix
Memory
Model
Description
_BIT_GROUP_
?BI?
All
Variables and arguments of type bit.
_DATA_GROUP_
?DT?
SMALL
Variables and arguments other than bit.
_PDATA_GROUP_
?PD?
COMPACT
Variables and arguments other than bit.
_XDATA_GROUP_
?XD?
LARGE
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.
当链接器覆盖函数数据内存并创建一个组时,该组将出现在链接器映射文件的内存映射部分中。

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.
组是基于函数的内存模型 (指定存储参数和变量的内存类) 以及用特定内存空间定义的任何变量创建的.

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.
如果您对某些段是否应覆盖有疑问,可以禁用这些段的覆盖。段覆盖可以被编译器、汇编器或链接器禁用。

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.
  • 当编译器优化级别设置为1 (使用optize编译器指令) 时,编译器不使用可覆盖的重定位类型。本地数据段不被覆盖。
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   导致汇编器仅在段定义中指定覆盖重定位类型时才创建覆盖段。从段定义中删除所有可覆盖的重定位类型,以避免覆盖数据段。
To disable overlaying in the linker...
在链接器中禁用覆盖...
n   The NOOVERLAY linker directive disables all data overlaying for the entire program.
n   Noverlay链接器指令禁用整个程序的所有数据覆盖。
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链接器指令,您可以操作由链接器生成的调用树。例如,覆盖 (sfname ! *) 将禁用sfname指定的函数的数据覆盖。


Manipulating the Call Tree
操作调用树
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.
在大多数情况下,链接器执行的调用树分析 (或叠加分析) 可以正常工作,不需要进行任何调整。然而,在某些情况下,覆盖算法无法确定程序的真正结构,并且必须使用链接器的覆盖指令手动调整调用树。
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指令允许您更改链接器在覆盖分析期间使用的调用引用。当您知道程序的结构时,使用覆盖指令很容易。程序结构或调用树反映在链接器映射文件的覆盖图部分列出的段中。
In general you must modify the call tree (using the OVERLAY directive) when:
通常,您必须在以下情况下修改调用树 (使用覆盖指令):
n   A pointer to a function is stored in a variable, table, or array.
n   指向函数的指针存储在变量、表或数组中。
n   The address of a function is passed or returned as function argument.
n   函数的地址作为函数参数传递或返回。
n   Your program includes a real-time operating system other than RTX51 or RTX51 Tiny.
n   你的程序包括除了RTX51或RTX51之外的实时操作系统。
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链接器使用RTX51RTX51-Tiny实时内核正确识别程序结构和应用程序的调用树,并为每个任务自动创建一个新根。
Function Pointers
函数指针
Function pointers (and indirectly-called functions) present some special issues that must be taken into consideration when creating functions that are called indirectly.
函数指针 (和间接称为函数) 提出了一些特殊问题,在创建间接调用的函数时必须考虑这些问题。
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  导致函数参数只能在寄存器中传递给间接调用的函数。可能不会使用覆盖函数参数和变量的典型参数传递方案,因为编译器不一定知道通过指针调用的函数的名称。
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.
默认情况下,Cx51编译器在寄存器中传递最多三个参数。不要假设任意三个参数都可以放入寄存器中。有关更多信息,请参考C51/CX51用户指南中的参数和寄存器。
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.
如果您需要的参数超过寄存器容纳的数量,则必须将它们合并到一个结构中,并传递一个指向该结构的指针。如果这是不可接受的,您可以使用可重入函数。
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.
由链接器自动生成的调用树必须使用OVERLAY指令进行调整,以包括对间接调用的函数的正确引用。
Note
  • If you attempt to pass more than three arguments through a pointer to a function, the compiler generates an error message.
  • 如果尝试通过指向函数的指针传递三个以上的参数,编译器将生成错误消息。
  • No warning or error is generated if you neglect to adjust the call tree when function pointers are used.
  • 如果在使用函数指针时忽略了调整调用树,则不会生成任何警告或错误。
There are two very good reasons why you must adjust the call tree if you use function pointers.
如果您使用函数指针,有两个很好的理由必须调整调用树。
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  链接器使用引用来构建调用树。如果函数初始化函数指针变量或将函数地址传递给另一个函数,链接器将其解释为引用,并将对该函数的调用添加到调用树中。稍后,当通过函数实际调用时,它将使用可能被更远处分支上的函数覆盖的数据空间,并导致数据损坏。如果您将函数指针作为参数传递,这甚至可能会破坏函数指针,从而可能导致程序崩溃。
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  在某些情况下,简单地禁用覆盖分析或简单地从调用树中删除通过指针调用的函数似乎更容易。但是,这会导致内存浪费。如果仅从调用树中删除函数,则必须记住,由间接调用的函数可能会覆盖它们的变量。如果管理不当,这也可能会导致数据损坏。
The easiest solution for indirectly-called functions is to remove them from the call tree. For example:
对于间接调用的函数,最简单的解决方案是将它们从调用树中删除。例如:

... OVERLAY (sfname-caller ~ (sfname-callee, sfname-callee)) ...

And, then add specific references from the calling functions to the indirectly-called function. For example:
然后将调用函数的特定引用添加到间接调用的函数中。例如:

... OVERLAY (sfname-caller ! (sfname-callee, sfname-callee)) ...

As an Argument
作为一个参数
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:
当函数指针被用作函数的参数时,链接器生成的调用树是不准确的。例如,给出以下示例程序:

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.
下面的流程图说明了正确的调用树。
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在主函数中引用,而不是在调用函数中引用,链接器会生成以下调用树和覆盖图。

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:
链接器调用树必须通过使用以下覆盖命令删除从main到indirect_func的引用并添加从调用者到indirect_func的引用来进行调整:

... OVERLAY(main ~ indirect_func, caller ! indirect_func) ...


After adjusting the call tree, the Overlay Map appears as follows:
调整呼叫树后,覆盖图显示如下:

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.
当将函数地址分配给局部变量 (函数指针) 时,在进行赋值的函数中创建引用。如果该函数也使用指针来调用分配给它的函数,则链接器生成的调用树是准确的。
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:
如果分配给指针的函数地址在另一个函数中使用 (通过返回或将其作为参数传递),链接器生成的调用树是不准确的。例如,给出以下示例程序:

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.
下面的流程图说明了正确的调用树。
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在主函数中引用,而不是在调用函数中引用,链接器会生成以下调用树和覆盖图。

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:
链接器调用树必须通过使用以下覆盖命令删除从main到indirect_func的引用并添加从调用者到indirect_func的引用来进行调整:

... OVERLAY(main ~ indirect_func, caller ! indirect_func) ...

After adjusting the call tree, the Overlay Map appears as follows:
调整呼叫树后,覆盖图显示如下:

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
在内存变量中
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:
当函数指针被分配给存储在内存中的全局变量 (DATA、IDATA、PDATA或XDATA) 时,链接器生成的调用树是不准确的。例如,给出以下示例程序:

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.
下面的流程图说明了正确的调用树。
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) 引用 (在本例中为函数指针fp)。它没有在调用函数中引用。因此,链接器生成以下调用树和覆盖图。

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的引用并添加从调用者到indirect_func的引用来调整链接器调用树:

... OVERLAY(?C_INITSEG ~ indirect_func, caller ! indirect_func) ...

After adjusting the call tree, the Overlay Map appears as follows:
调整调用树后,覆盖图显示如下:

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函数。但是,如果fp通过主函数中的代码初始化,则主函数将引用indirect_func函数。
  • 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.
  • 在这个示例中,初始化代码中仅引用了indirect_func,因为fp变量实际上已初始化。这将是所有存储在内存中的函数指针的情况。如果fp的内存类型更改为代码 (以便将指针存储在ROM),则初始化代码将没有引用。相反,将会有一个来自源文件代码段的引用 (文件名)。当函数指针存储在ROM变量中时,需要注意细微的区别。
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:
当一个函数指针被分配给一个存储在ROM (CODE) 中的全局变量时,链接器生成的调用树可能是完全准确的。例如,给出以下示例程序:

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.
下面的流程图说明了正确的调用树。
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由包含函数指针fp的主源文件 (?co?main) 的代码段引用。它没有在调用函数中引用。但是,调用函数确实引用了fp变量。因此,链接器生成以下调用树和覆盖图。

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.
这个?CO?MAIN段包含在MAIN.C文件中声明的所有代码变量。如果这仅由函数指针组成,所有这些指针都由C函数访问,则不需要更改调用树。请参考以下有关存储在代码中的全局函数指针的规则,以确定是否需要调整调用树。
n   Global function pointers assigned to CODE memory may be the only variables declared in a source file.
n   分配给代码内存的全局函数指针可能是源文件中声明的唯一变量。
n   Function pointers declared must all be used (or have the potential to be used) in the function or functions that reference them.
n   声明的函数指针必须全部在引用它们的函数中使用 (或有可能使用)。
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   如果在函数中使用了一些函数指针,但不是全部,则必须手动调整调用树以反映此关系。否则,宝贵的内存会被不准确的调用树浪费掉。
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源文件 (甚至来自另一个源文件) 中任何全局代码变量的引用在调用树中都通过对?的引用来指示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.
链接器在删除没有引用的段之间的引用时遇到错误

Cause
This message is caused when the OVERLAY directive is used to delete a reference between two segments that do not reference each other.
当使用OVERLAY指令删除不相互引用的两个段之间的引用时,会导致此消息。

Resolution
Remove the OVERLAY parameter that attempts to delete the reference between the specified segments.
移除尝试删除指定段之间参考的OVERLAY参数。
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表