Changes between Initial Version and Version 1 of howto/Linker_scripts_MAP_files


Ignore:
Timestamp:
Oct 20, 2015, 1:05:46 PM (9 years ago)
Author:
welsh
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • howto/Linker_scripts_MAP_files

    v1 v1  
     1= Understanding Linker Command Files (Linker Scripts) / MAP files =
     2
     3For most people, linking a program (i.e. the step that takes the compiled object files and creates an executable program) is a little bit like magic.  There are a lot of automated tools that handle everything and rarely are there ever any issues.  However, in complex embedded systems, it can become necessary to dig in and understand how to control how your program is linked. 
     4
     5For example, in the 802.11 Reference design, the upper level MAC code required CPU High to have 256 KB of LMB memory.  However, XPS could not build a design that contained a single 256 KB LMB memory.  The memory size was too large to meet timing given all the other logic and constraints within the system.  Therefore, we had to split the 256 KB memory into two 128 KB physical memories located contiguously within the processor memory map and then use the Linker Command File (Linker Script) to control which sections of the program to load into each memory.  This required editing and understanding the Linker Command File (Linker Script) and using the MAP files generated as part of the linker output.
     6
     7This tutorial should give a basic understanding of Linker Command Files (Linker Scripts) and MAP files.  You can find additional information on the Linker Command Files (Linker Scripts) and MAP files by searching on the Internet.
     8
     9NOTE:  This tutorial is based on [wiki:802.11/Download 802.11 Reference Design v1.3.0] but the concepts should apply generically. 
     10
     11== Linker Command Files ==
     12
     13'''Opening the Linker Command File (Linker Script):'''
     14
     15Open the Linker Command file for a project by expanding the project in the "Project Explorer" window and finding the {{{lscript.ld}}} file inside the {{{src}}} folder.  By default, double-clicking the {{{lscript.ld}}} file will open the Linker Command File in the SDK "Linker Script Editor".  Unfortunately, this editor does not give the granularity of control that is needed for advanced manipulation of Linker Command File.  Instead, right-click on the {{{lscript.ld}}} file and select "Open with" --> "Text Editor".  This will open the file in a generic text editor within the SDK. 
     16
     17[[Image(linker_script_edit.png, 600px)]]
     18
     19If you do not have the SDK open, you can find the Linker Command File for the 802.11 Reference design v1.3.0 [http://warpproject.org/trac/browser/ReferenceDesigns/w3_802.11/c/wlan_mac_high_ap/lscript.ld?rev=4628 here].
     20
     21NOTE:  The Linker Command File (Linker Script) used in the 802.11 Reference Design was originally generated by the SDK Linker Script Editor and then manually edited.  The Linker Script Editor is very useful for simple designs.  However, for more complicated designs, manual editing is required. 
     22
     23The best practice we have found is to let the SDK Linker Script Editor generate the initial Linker Command File (Linker Script) and then manually edit where required.
     24
     25
     26'''Understanding the Linker Command File (Linker Script):'''
     27
     28The Linker Command File (Linker Script) is organized into sections:
     29
     30For this section, we look at the Linker Command File (Linker Script) for the AP project (i.e. wlan_mac_high_ap).
     31
     321. The first section defines the sizes for the Stack and the Heap used by the program:
     33{{{
     34_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x1000;
     35_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x4000;
     36}}}
     37  By default, for the AP project, the 802.11 Reference design allocates a 4 KB stack and a 16 KB heap so that there are no issues with function variables placed on the stack or dynamically allocated memory from the heap.  These are larger than what the reference design actually uses so it is easy to extend the design without running into stack or heap issues, which can be difficult to debug.
     381. The next section defines the memories in the system that can be used to place code and data.  These sections correspond to the physical memories that were defined in the XPS project:
     39{{{
     40MEMORY
     41{
     42   mb_high_ilmb_bram_cntlr_0_mb_high_dlmb_bram_cntlr_0 : ORIGIN = 0x00000050, LENGTH = 0x0001FFB0
     43   mb_high_ilmb_bram_cntlr_1_mb_high_dlmb_bram_cntlr_1 : ORIGIN = 0x00020000, LENGTH = 0x00020000
     44   mb_high_init_bram_ctrl_S_AXI_BASEADDR : ORIGIN = 0x50000000, LENGTH = 0x00001000
     45   pkt_buff_tx_bram_ctrl_S_AXI_BASEADDR : ORIGIN = 0xBF570000, LENGTH = 0x00010000
     46   pkt_buff_rx_bram_ctrl_S_AXI_BASEADDR : ORIGIN = 0xBF560000, LENGTH = 0x00010000
     47   mac_log_bram_ctrl_S_AXI_BASEADDR : ORIGIN = 0x90000000, LENGTH = 0x00002000
     48   mb_high_aux_bram_ctrl_S_AXI_BASEADDR : ORIGIN = 0xBF540000, LENGTH = 0x00010000
     49   ddr3_sodimm_S_AXI_BASEADDR : ORIGIN = 0xC0000000, LENGTH = 0x40000000
     50}
     51}}}
     52  From this, you can see the two 128 KB LMB memories defined for CPU High as well as other memories such as the DDR.
     531. The next section specifies the default program entry point:
     54{{{
     55ENTRY(_start)
     56}}}
     57  This should be left alone since it is part of the build configuration of the SDK. 
     581. The last section defines all the Linker "Sections".  A global variable or function can be placed in a give "section" by using the pragma:  {{{__attribute__ ((section (".my_data")))}}}.  By default, the SDK build setup defines a number of default sections that are used to place code and data.  Looking at the ".text" section:
     59{{{
     60.text : {
     61   *(.text)
     62   *(.text.*)
     63   *wlan_mac_common*(.text)
     64   *(.gnu.linkonce.t.*)
     65} > mb_high_ilmb_bram_cntlr_0_mb_high_dlmb_bram_cntlr_0
     66}}}
     67  we can see a few thing: 
     68    1. The section is placed in the memory:  {{{mb_high_ilmb_bram_cntlr_0_mb_high_dlmb_bram_cntlr_0}}} that was defined in the MEMORY section above.
     69    1. The section uses wildcards and pattern matching to assign code to that section.  A couple notes on wildcards and pattern matching:
     70      a. Wildcards are "greedy" (i.e. they will match all code / data that has not previously been assigned).  Therefore, entries like {{{*(.text)}}} or {{{*(.text.*)}}} will allocate any unallocated code and should be used after all other code has been allocated to other sections.
     71      b. Section order matters in the Linker Command File (Linker Script).  For example, in the example Linker Command File, the {{{.text_bram_1}}} section comes before the {{{.text}}} section so that some of the code can be allocated to {{{mb_high_ilmb_bram_cntlr_1_mb_high_dlmb_bram_cntlr_1}}} vs {{{mb_high_ilmb_bram_cntlr_0_mb_high_dlmb_bram_cntlr_0}}}
     72  Next, if we look at a section like ".heap":
     73{{{
     74.heap (NOLOAD) : {
     75   . = ALIGN(8);
     76   _heap = .;
     77   _heap_start = .;
     78   . += _HEAP_SIZE;
     79   _heap_end = .;
     80} > mb_high_ilmb_bram_cntlr_1_mb_high_dlmb_bram_cntlr_1
     81}}}
     82  we can see a few things:
     83    1. The heap is not initialized due to the {{{NOLOAD}}} directive (i.e. it is initialized to the default BRAM state).
     84    1. The section can be aligned within the memory map using the {{{ALIGN}}} directive.
     85    1. Symbols can be declared that can be then used in the [http://warpproject.org/trac/browser/ReferenceDesigns/w3_802.11/c/wlan_mac_high_framework/wlan_mac_high.c?rev=4628#L47 C code].
     86    1. {{{_HEAP_SIZE}}} bytes, declared above, are allocated by incrementing the current point in memory (i.e. the {{{. += _HEAP_SIZE;}}} line).
     87    1. The section is allocated in the {{{mb_high_ilmb_bram_cntlr_1_mb_high_dlmb_bram_cntlr_1}}} memory.
     88
     89By understanding the Linker Command File (Linker Script), it is possible to control how code and data is allocated and placed within memory.  This can come in handy when there are hardware limitations to the amount of BRAM that can be allocated to a given physical memory.
     90
     91
     92'''Limitations on DDR:'''
     93
     94Only on-chip BRAM can be initialized by the bitstream that is created from the linked program.  Therefore, if the program needs to allocate memory in DDR using the linker, there are a some restrictions that must be placed on that memory:
     951.  If the memory needs to be initialized, then it must be done so by the program itself. 
     961.  The initial value of the memory must be assumed to be random unless initialized by the program.
     97
     98This is different from BRAM in that the bitstream will initialize BRAM to the value dictated by the program (and zero otherwise).  Hence, no code can be placed in DDR, only data that can be initialized by the program.  To declare a data section in DDR, it must be specified as "NOLOAD" so that the program that builds the bitstream does not try to do anything with it.  For example, a data section for CPU High in the DDR would look like:
     99{{{
     100.cpu_high_ddr_linker_data (NOLOAD) : {
     101   __cpu_high_ddr_linker_data_start = .;
     102   *(.my_data)
     103   __cpu_high_ddr_linker_data_end = .;
     104} > ddr3_sodimm_S_AXI_BASEADDR
     105}}}
     106The symbols are declared so that it is easy to check programatically that the linked section does not exceed any predefined allocation of DDR, in the case that DDR is being allocated statically within the program.
     107
     108== MAP files ==
     109
     110A MAP file is an output of the Linker that gives information about the symbols, addresses, and allocated memory in the generated ELF file.  It is extremely useful when trying to understand and debug linker issues related to code size.  For example, if you get an error from the linker similar to:
     111{{{
     112c:/xilinx/14.4/ise_ds/edk/gnu/microblaze/nt64/bin/../lib/gcc/microblaze-xilinx-elf/4.6.2/../../../../microblaze-xilinx-elf/bin/ld.exe:
     113wlan_mac_high_ap.elf section `.abcd' will not fit in region `mb_high_ilmb_bram_cntlr_1_mb_high_dlmb_bram_cntlr_1'
     114c:/xilinx/14.4/ise_ds/edk/gnu/microblaze/nt64/bin/../lib/gcc/microblaze-xilinx-elf/4.6.2/../../../../microblaze-xilinx-elf/bin/ld.exe:
     115region `mb_high_ilmb_bram_cntlr_1_mb_high_dlmb_bram_cntlr_1' overflowed by x bytes
     116}}}
     117then using a MAP file to understand the memory usage of the program is helpful.
     118
     119'''Generating a MAP file:'''
     120
     121By default, MAP files are not generated by an SDK project.  To enable MAP file generation, linker flags must be added to the project:
     122  1. Right click on the project to modify in the "Project Expolorer" window and select "Properties".  This will open a new dialog box with all of the properties for the project.
     123  1. Under "C/C++ Build" select "Settings"
     124  1. Under "Tool Settings" --> "MicroBlaze gcc linker" select "Miscellaneous"
     125  1. In the "Linker Flags" dialog add: {{{-Wl,-Map=executable.map}}}, where "exectuable.map" is the name of the MAP file to use.
     126  1. Click "OK" and the SDK will re-link your project and create the "exectuable.map" file.
     127
     128[[Image(adding_map_file.png, 600px)]]
     129
     130For all WARP reference designs, we add these linker flags to each project. 
     131
     132'''Opening a MAP file:'''
     133
     134Open the MAP file for a project by expanding the project in the "Project Explorer" window and finding the {{{executable.map}}} file inside the {{{Debug}}} folder.  By default, double-clicking the {{{executable.map}}} file will result in an error.  Instead, right-click on the {{{executable.map}}} file and select "Open with" --> "Text Editor".  This will open the file in a generic text editor within the SDK. 
     135
     136[[Image(map_file_edit.png, 600px)]]
     137
     138'''Understanding a MAP file:'''
     139
     140The MAP file is organized into sections:
     141
     142For this section, we look at the MAP file for the AP project (i.e. wlan_mac_high_ap).
     143
     1441.  The first section details all of the members included from the various archive files in the system:
     145{{{
     146Archive member included because of file (symbol)
     147
     148../../wlan_bsp_cpu_high/mb_high/lib\libxil.a(xil_printf.o)
     149                              ./wlan_mac_high_framework/wlan_exp_common.o (xil_printf)
     150...
     151}}}
     152  This information is not especially useful, but lets you see all the system functions.
     1531. The next section shows the names and sizes of global symbols (ie global variables) that have been allocated in the program:
     154{{{
     155Allocating common symbols
     156Common symbol       size              file
     157
     158UartLite            0x4c              ./wlan_mac_high_framework/wlan_mac_high.o
     159cdma_inst           0x164             ./wlan_mac_high_framework/wlan_mac_high.o
     160async_pkt_enable    0x4               ./wlan_mac_high_framework/wlan_exp_node.o
     161mac_param_chan      0x4               ./src/wlan_mac_ap.o
     162statistics_table    0xc               ./src/wlan_mac_ap.o
     163my_bss_info         0x4               ./src/wlan_mac_ap.o
     164ipc_msg_from_low    0x8               ./wlan_mac_high_framework/wlan_mac_high.o
     165ipc_msg_from_low_payload
     166                    0x190             ./wlan_mac_high_framework/wlan_mac_high.o
     167...
     168}}}
     169  This is a good place to check that all global variables have expected sizes.  A common mistake can be to unknowingly allocate a large global variable that consumes a lot of memory space.
     1701. The next section show the memory configuration.  This should be the same as in the Linker Command File:
     171{{{
     172Memory Configuration
     173
     174Name             Origin             Length             Attributes
     175mb_high_ilmb_bram_cntlr_0_mb_high_dlmb_bram_cntlr_0 0x00000050         0x0001ffb0
     176mb_high_ilmb_bram_cntlr_1_mb_high_dlmb_bram_cntlr_1 0x00020000         0x00020000
     177mb_high_init_bram_ctrl_S_AXI_BASEADDR 0x50000000         0x00001000
     178...
     179}}}
     1801. Finally, the last section details the memory map split out by section defined in the Linker Command file:
     181{{{
     182Linker script and memory map
     183
     184...
     185
     186.text_bram_1    0x00020000    0x103a8
     187 *wlan_mac_high_framework*(.text)
     188 .text          0x00020000      0x310 ./wlan_mac_high_framework/wlan_exp_common.o
     189                0x00020000                wlan_exp_print_header
     190                0x00020114                wlan_exp_print_mac_address
     191                0x00020190                wlan_exp_set_print_level
     192                0x000201e0                wlan_exp_get_mac_addr
     193                0x00020214                wlan_exp_put_mac_addr
     194                0x0002025c                wlan_exp_configure
     195                0x000202b8                get_station_status
     196
     197...
     198
     199.text           0x00000050    0x183b8
     200 *(.text)
     201 .text          0x00000050       0x34 c:/xilinx/14.4/ise_ds/edk/gnu/microblaze/nt64/bin/../lib/gcc/microblaze-xilinx-elf/4.6.2/../../../../microblaze-xilinx-elf/lib/bs/m/le/crt0.o
     202                0x00000050                _start1
     203                0x00000080                _exit
     204 .text          0x00000084        0x0 c:/xilinx/14.4/ise_ds/edk/gnu/microblaze/nt64/bin/../lib/gcc/microblaze-xilinx-elf/4.6.2/bs/m/le/crti.o
     205 .text          0x00000084      0x118 c:/xilinx/14.4/ise_ds/edk/gnu/microblaze/nt64/bin/../lib/gcc/microblaze-xilinx-elf/4.6.2/bs/m/le/crtbegin.o
     206 .text          0x0000019c       0xb0 c:/xilinx/14.4/ise_ds/edk/gnu/microblaze/nt64/bin/../lib/gcc/microblaze-xilinx-elf/4.6.2/../../../../microblaze-xilinx-elf/lib/bs/m/le/crtinit.o
     207                0x0000019c                _crtinit
     208 .text          0x0000024c      0x604 ./wlan_mac_common/wlan_mac_ipc_util.o
     209                0x0000024c                nullCallback
     210                0x00000254                MailboxIntrHandler
     211                0x000002d8                wlan_lib_mailbox_setup_interrupt
     212
     213...
     214
     215.heap           0x00037ca0     0x4000
     216                0x00037ca0                . = ALIGN (0x8)
     217                0x00037ca0                _heap = .
     218                0x00037ca0                _heap_start = .
     219                0x0003bca0                . = (. + _HEAP_SIZE)
     220 *fill*         0x00037ca0     0x4000 00
     221                0x0003bca0                _heap_end = .
     222
     223.stack          0x0003bca0     0x1000
     224                0x0003bca0                _stack_end = .
     225                0x0003cca0                . = (. + _STACK_SIZE)
     226 *fill*         0x0003bca0     0x1000 00
     227                0x0003cca0                . = ALIGN (0x8)
     228                0x0003cca0                _stack = .
     229                0x0003cca0                __stack = _stack
     230                0x0003cca0                _end = .
     231
     232...
     233}}}
     234  As you can see, this gives a wealth of information about where everything is mapped in the program.  Each top level section, such as {{{.text}}} or {{{.heap}}} has both the starting address in the memory map as well as the size (in bytes) listed.  Then each section is broken down into the individual object files and both the starting address and size is listed.  Finally, each object file is broken down into the individual functions within the object file and the starting address for each function is listed.  This allows you to understand which object files might contain large functions which are not necessary for your program execution.  It can also give context when looking at pointer addresses within the program. 
     235
     236MAP files are a great source of information when debugging your program.  While they are extremely dense and can be a little intimidating, understanding and using MAP files can give you a lot of information that is otherwise difficult to get in standard program debug.
     237
     238If you have any questions, please use the [http://warpproject.org/forums/ forums].
     239
     240