This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Retain pragma / linker option doesn't seem to work

Other Parts Discussed in Thread: EK-TM4C1294XL, TM4C1294NCPDT


Board: EK-TM4C1294XL
AppEnv: TI_RTOS+NDK

The goal I had set for my commandline (CLI) subsystem was to be able to have link-time determination of which commands are included in the exec build (unlike some of the example code where a table as to be defined in C).

Here is how individual commands are compiled

In PdbCli.h:

// From processors.wiki.ti.com/.../Pragmas_in_C%2B%2B
#define PRAGMA(x) _Pragma(#x)
#ifdef __cplusplus
#define DSPRAGMA(f,s) PRAGMA(DATA_SECTION(s))
#else
#define DSPRAGMA(f,s) PRAGMA(DATA_SECTION(f, s))
#endif

#define PDBCLI_REG(NAME, FUNC, ARGS...) \
DSPRAGMA(pdbcli_reg_ ## NAME, ".data_pdbcli") \
PRAGMA(RETAIN(pdbcli_reg_ ## NAME)) \
cliEntry_T pdbcli_reg_ ## NAME = { #NAME , FUNC ,##ARGS }


In various C modules:
#include "PdbCli.h"
static int PdbCliHi(CliCtxt_T ctxt, int argc, char *argv[])
{
PdbCliPrintf(ctxt, "ho\n");
return PDBCLI_RET_OK;
}
PDBCLI_REG(testcmd, PdbCliHi, "Greet the CLI",
"This is your chance for deep conversation with the\n"
"command line interface. You say \"Hi\", the response\n"
"will astound you\n");

 

I modified linker command file as follows (orig comments removed):

--retain=g_pfnVectors

MEMORY
{
FLASH (RX) : origin = 0x00000000, length = 0x00100000
SRAM (RWX) : origin = 0x20000000, length = 0x00040000
}

SECTIONS
{
.intvecs: > 0x00000000
.text : > FLASH
.const : > FLASH
.cinit : > FLASH
.pinit : > FLASH
.init_array : > FLASH
.vtable : > 0x20000000
.data : > SRAM
.data_pdbcli : > SRAM,
LOAD_START(PdbCli_Commands_start),
LOAD_SIZE(PdbCli_Commands_len)
.bss : > SRAM
.sysmem : > SRAM
.stack : > SRAM
}

__STACK_TOP = __stack + 512;



  • When I build a monolithic executable - all works fine (all pdb_cli_reg_* structs are in the final map file)
  • When I place commands in an executable (directly referenced C module) that is otherwise referenced - all works fine
  • When I place commands in the lib, within an object file that is otherwise referenced - all works fine
  • When I place commands in the lib, within an object file that is NOT otherwise referenced, the symbols are not retained regardless of the above pragma

I confirmed, using `objdump` that the pdbcli_reg_* variables are in the

library, marked with 'retain'

What I have tried:

  • Tried adding --retain='*(.data_pdbcli)' to the linker command file
  • Tried adding --retain='*<*>(.data_pdbcli)' to the linker command file
  • Tried adding --retain='pdbcli_reg*' to the linker command file
  • Tried other variations and flags to no avail

Reproduced in Linux and WIndows CCS environments

Link line from build log:

"C:/ti/ccsv6/tools/compiler/ti-cgt-arm_5.2.4/bin/armcl" -mv7M4 --code_state=16 --float_support=FPv4SPD16 --abi=eabi -me -g --gcc --define=ccs="ccs" --define=PART_TM4C1294NCPDT --define=ccs --define=TIVAWARE --display_error_number --diag_warning=225 --diag_wrap=off --gen_func_subsections=on -z -m"CommonFWLibTest.map" --heap_size=0 --stack_size=512 -i"C:/ti/ccsv6/tools/compiler/ti-cgt-arm_5.2.4/lib" -i"C:/ti/ccsv6/tools/compiler/ti-cgt-arm_5.2.4/include" --reread_libs --warn_sections --display_error_number --diag_wrap=off --xml_link_info="CommonFWLibTest_linkInfo.xml" --rom_model -o "CommonFWLibTest.out" "./PdbCli_Test.obj" "../EK_TM4C1294XL.cmd" -l"./configPkg/linker.cmd" -l"libc.a" -l"C:/cygwin64/home/nhed/Projects/TI_CommonFW/libtest/proj/../../lib/proj/Debug/CommonFWLib.lib" -l"C:/ti/tirtos_tivac_2_12_01_33/products/TivaWare_C_Series-2.1.0.12573c/driverlib/ccs/Debug/driverlib.lib" -l"C:/ti/tirtos_tivac_2_12_01_33/products/TivaWare_C_Series-2.1.0.12573c/usblib/ccs/Debug/usblib.lib"

I saw other posts with similar issues but no clear answer

Thanks

  --Nevo

  • I'm not 100% certain this post will solve your problem.  But I have a lot of confidence in it.

    The linker invocation ends by listing one object file ...

    Nevo Hed said:
    "./PdbCli_Test.obj"

    then a few command files (which I presume do not list further object files), and a few libraries.  Members of a library are brought into the link only to satisfy references to undefined symbols in PdbCli_Test.obj.  This process can repeat itself.

    To make this a bit more concrete, here is an example with made up symbol names.  Suppose PdbCli_Test.obj calls the function in_lib.  The linker brings in whatever library member has the function in_lib.  Suppose the function in_lib calls the function in_different_lib.  The linker brings in whatever library member has the function in_different_lib.  And so it goes, until the linker brings in the functions that don't call anything.  The same thing can happen for a reference to data, though that is less common in practice.

    This process of satisfying symbol references is the only way that code in a library is included in the link.

    While I don't know for certain, it is very likely you expect the linker to bring in functions from the library which have no references from PdbCli_Test.obj.  You tell the linker to do that with the option --undef_sym=symbol_name.  Read about that option in the ARM assembly language tools manual.  

    Thanks and regards,

    -George

  • Thanks George

    I understand the general behavior of a linker and have no qualms with your description.  I was hoping that the "retain" linker flags and pragmas help bypass that behavior for CERTAIN symbols. 

    I want to be able to specify this set of symbols either by:

    • wildcard on their name (name matching "pdbcli_reg_*")
    • having them been tagged for a certain section
    • some other in-code mechanism like pragma

    I was hoping that the "retain" flags would be able to cause these symbols to be pulled in.

    Are you saying that the retain flags and pragma only impact symbols present in objects that have already been marked for linkage but are otherwise referenced (sounds like a narrow condition).

    as the  --undef_sym= flag is not documented to accept any wildcards I doubt that it will satisfy my needs

    If there is none I suspect that I could write a linker wrapper script that finds the names of all the pdbcli_reg_* variable names in the libs and --undef_sym them but that sounds a bit painful.

       Thanks

    p.s. of the few posts that discussed the --retain flag I was left with the impression that others expected a similar behavoir

  • Nevo Hed said:
     I was hoping that the "retain" linker flags and pragmas help bypass that behavior for CERTAIN symbols. 

    They do not.

    An object file can be presented to the linker two ways.  One way is on the command line.  (Any object files that appear in command files are equivalent to those on the command line.)  The other way is for the object file to be brought in from a library because it satisfies an open symbol reference (as I described in my previous post).  When an object file is brought in, all of the sections in the entire file are potentially part of the final image.  Then the linker attempts to eliminate sections within the object file that are not needed.  This is where the retain section feature (pragma, flag, assembler directive, etc) comes in.  A retain section feature can cause a section to continue to be part of the link, even though there are no references to that section.  A retain section feature can never, by itself, cause a file to be brought in from a library.

    Nevo Hed said:
    the  --undef_sym= flag is not documented to accept any wildcards

    Unfortunately, this is correct.

    Thanks and regards,

    -George

  • Thanks George

    I went ahead and implemented a wrapper script that dumps the symbol names for all libs (using armnm) and matches the wildcard there, then adds an '--undef_sym=' for each one.  Works, but slow.

    --Nevo

  • Hi Nevo,

    I have the same .retain issue. And, here is my solutions for your reference.

    I have an assembly file which contains an interrupt vector table and some exception handlers. This assembly file with some C files are compiled and archived to a library. As your situation, even the ".retain" directive placed in this assembly file, the interrupt table and exception handlers are still removed in the final output. It is sad.

    Ok, my first solution is to add a "dummy" function in the assembly file. And, a C function (which is sure to be called in the final output) call the dummy function.

    In assembly file:

    .global dummy
    dummy:
    BX LR

    In C file:
    void func(void)
    {
    dummy()
    ...
    }

    Now, the linker will link the dummy() function from the assembly file. Since dummy() is in the same object file with the interrupt vector and handlers, all the retained sections will also be included in the final output even they are not called directly.

    OK, this solution works for me. But it is ugly. The 2nd solution is to use "--undef_sym" flag. So, I remove the dummy function and add a global label "INTVECT" in the interrupt table.

    .sect ".vect"
    .retain
    .global __VECT
    __VECT:
    .word __STACK_END
    .word _c_int00
    ...

    In the linker command file, add --undef_sym flag

    --undef_sym=__VECT

    Since all the handler symbols are used by the vector table and the vector table is to be included in the final output by using undef_sym flag. As a result, all the handlers are also included in the final output.

    This is a beautiful solution for me.

    For your situation, I believe you can find a similar solution without using a wrapper script.
  • Thanks rfocus

    Your solution is fine if there is only one symbol (or many symbols in one module), in my case the symbols can be spread over many modules over several libs. Unless I auto generate the linker command script (in a wrapper or via xdc which I have no experience in)

    The wrapper script works beautifully for me, in addition to solving the above issue I also the script to package build info into the image (build time, host, user, repo, etc)

    Thanks again
    --Nevo