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.

RTOS/PROCESSOR-SDK-AM335X: Undefined reference to UART_stdioInit

Part Number: PROCESSOR-SDK-AM335X
Other Parts Discussed in Thread: SYSBIOS

Tool/software: TI-RTOS

Hello,

(First off, that cute little "Ask a related question"  doesn't work.  It just takes me a an empty screen, with a title, and that nav area on bottom...)

Two projects.  One uses "System_printf" and it works fine.  An older Sys/Bios project that was doing USB stuff.  So I import a new demo project "MMCSD" in order to learn it's use.  Well, it uses 

#define MMCSD_log                UART_printf

(Why someone felt the need to obfuscate UART_printf  by hiding it in header, and defining it as something else, is beyond me...)

Well, any messages are not showing up on the CCS console, like the older project.  So I replace the "MMCSD_log" with "System_printf"...  Opps.  Now it tells me "undefined reference to `UART_stdioInit'"

So I do the logical thing.  I go into the MAP file of the one that works, and search for "UART_stdioInit"  After all, any NORMAL programmer would figure that they could use the map file to find out how it was linked, and then figure out how to add that library.  Well, nope.  It doesn't exist it the map file.

So, either it's not really needed by the older project that works, and the new project suddenly THINKS it needs it, or, yet again, someone decided to obfuscate it by changing it's name in some header file  (after all, that was also done with System_printf deep in some header file) 

#define System_printf xdc_runtime_System_printf

(But at least a text search can find it)

So, the working project uses "System_printf" without any linker error, but the new demo project when I try to use "System_printf" for some reason thinks it needs to link this in.

I tried e2e.ti.com/.../395152

But that line is ALREADY in my CFG file of the new demo project that doesn't work.  So that is NOT the answer.

What is the magic, secret to simply adding a "System_printf" and not causing linker errors?  Because (again, I am complaining) the XGCONF and SYSYBIOS tools are hiding any ability to control the build environment, and anytime I try to think outside the restricted world of XGCONF, it fails miserably.  And documentation is a nightmare to find...

(Any time I try to deviate from the narrow path of the examples, my blood pressure goes way up...)

I have included the ZIP of the project that has the source and the CFG, and anything else...

MMCSD_bbbAM335x_EMMC_armTestproject.zip

  • Chris,

    It appears that the project is missing Semihosting module which is commented out in your .cfg and make sure that library rdimon is linked.

    Checkout the articles corresponding to "How do I enable Semi-Hosting for Cortex-A GNU targets ?" and "Why is System_printf()/printf() not working ?"
    in the wiki created by TI RTOS team for usage of system_printf on ARM platforms using GCC compiler.
    processors.wiki.ti.com/.../BIOS_with_GCC_(CortexA)

    If you are still running into issues, we can provide further guidance on your build issues.

    Regards,
    Rahul

    PS: The obfuscation of the MMCSD_log was done precisely to allow users to re-direct logs to either CCS console or to UART by default it is configured for UART because we test these examples from SD boot with no CCS connection through an emulator so we need the ability to read the logs directly from serial console rather than CCS console. In debug/development environment user have the flexibility to not connect UART and directly debug their code using CCS console by undefining IO_CONSOLE as you have done.
  • Rahul,

    Thanks for the quick reply.  But it doesn't work.

    (This isn't *my* cfg file, this is out of the box example code.  And the CFG file is a mess, I normally keep files cleaner than that.)

    I un-commented the  "var SemihostSupport = xdc.useModule('ti.sysbios.rts.gnu.SemiHostSupport');"  and added "rdimon" to the Linker/Libraries.  Still the same failure:

    makefile:151: recipe for target 'MMCSD_bbbAM335x_EMMC_armTestproject.out' failed
    C:\ti\pdk_am335x_1_0_7\packages\ti\board\lib\bbbAM335x\a8\release\ti.board.aa8fg(bbbAM335x_lld_init.oa8fg): In function `Board_uartStdioInit':
    bbbAM335x_lld_init.c:(.text.Board_uartStdioInit+0x10): undefined reference to `UART_stdioInit'
    collect2.exe: error: ld returned 1 exit status

    I then removed "nosys" as the WiKi says.  Still the same failure. 

    Except for step 7 in the link, which: A)  is after a successful build anyway, which I can't even get to and B)  I have no idea where "Program/Memory Load Options"  is.  Absolutely nothing in my CCS 7.2 looks like that screen shot.

  • Followup.  Still not fixed... But comments into your "PS"

    Rahul Prabhu said:
    Chris,

    PS: The obfuscation of the MMCSD_log was done precisely to allow users to re-direct logs to either CCS console or to UART by default it is configured for UART because we test these examples from SD boot with no CCS connection through an emulator so we need the ability to read the logs directly from serial console rather than CCS console. In debug/development environment user have the flexibility to not connect UART and directly debug their code using CCS console by undefining IO_CONSOLE as you have done.

    I didn't uncomment the IO_CONSOLE, it came that way. But I would expect no console in this anyway.
    The concept makes sense, but would have been nice to see a comment..

    #ifndef IO_CONSOLE
          /*  Select one of the following for debug messages:  */
    //#define MMCSD_log                UART_printf              /*  Use this to print to the UART */
    #define MMCSD_log                System_printf              /* Use this to print to the debugger (whatever "semihosting" means)  */
    #else
    #define MMCSD_log                printf
    #endif

    I was going to do this anyway, but wasn't sure what else it might break.  Everything seems so precarious, I live is fear of even changing one thing in a demo program, as it'll break.

    Project attached, with those itty-bitty changes, that didn't help.

    3704.MMCSD_bbbAM335x_EMMC_armTestproject.zip

  • Rahul ,

    Words cannot describe how annoyed I get dealing with these brittle examples... 

    Here is how to easily break the "MMCSD_bbbAM335x_EMMC_armTestproject"

    1. Import the project

    2. Build it

    3. After three days of pulling out your hair trying to make a minor change, you just decide you don't even want that logging.  You will just use the debugger, since you can't get "System_printf" to work anyway

    4. SCRAP ALL THE PROJECT AND RE-IMPORT IT AGAIN.

    5.  In  MMCSD_log.h line 68/68 do this (after all this is WHY the obfuscation was done, per the initial reply ):

    #ifndef IO_CONSOLE
    //                         #define MMCSD_log                UART_printf
    #define MMCSD_log				DummyLog
    #else
    #define MMCSD_log                printf
    #endif

    6.  Comment out the one and only place that UART_stdioInit() appears anywhere in the project, in MMCSD_log.c:

    void ConsoleUtilsInit(void)
    {
        //CSW   UART_stdioInit(0);
    }

    7. Create your own "dummyLog" function wherever you want, but inside MMCSD_log.c is a logical choice:

    int DummyLog(const char *fmt, ...) { return 0;}

    (And toss a function prototype into the MMCSD_log.h header file, just for good measure. Because every warning should be eliminated too, right??)

    8.  Clean, Build, and watch it no longer be able to link.

    'Building target: MMCSD_bbbAM335x_EMMC_armTestproject.out'
    'Invoking: GNU Linker'
    "C:/ti/gcc-arm-none-eabi-4_9-2015q3/bin/arm-none-eabi-gcc.exe" -mtune=cortex-a8 -marm -Dam3359 -DMEASURE_TIME -DSOC_AM335x -DbbbAM335x -g -gdwarf-3 -gstrict-dwarf -Wall -finstrument-functions -MMD -MP -mfloat-abi=hard -Wl,-Map,"MMCSD_bbbAM335x_EMMC_armTestproject.map" -nostartfiles -static -Wl,--gc-sections -L"C:/ti/bios_6_46_05_55/packages/gnu/targets/arm/libs/install-native/arm-none-eabi/lib/fpu" -L"/packages/gnu/targets/arm/libs/install-native/arm-none-eabi/lib/fpu" -Wl,--defsym,STACKSIZE=0x1C000 -Wl,--defsym,HEAPSIZE=0x400 -o"MMCSD_bbbAM335x_EMMC_armTestproject.out" "./GPIO_soc.o" "./I2C_soc.o" "./MMCSD_soc.o" "./UART_soc.o" "./main_emmc.o" "./profiling.o" "./logging/MMCSD_log.o" -Wl,-T"configPkg/linker.cmd" -Wl,--start-group -lrdimon -lgcc -lm -lnosys -lc -Wl,--end-group 
    makefile:154: recipe for target 'MMCSD_bbbAM335x_EMMC_armTestproject.out' failed
    C:\ti\pdk_am335x_1_0_7\packages\ti\board\lib\bbbAM335x\a8\release\ti.board.aa8fg(bbbAM335x_lld_init.oa8fg): In function `Board_uartStdioInit':
    bbbAM335x_lld_init.c:(.text.Board_uartStdioInit+0x10): undefined reference to `UART_stdioInit'
    collect2.exe: error: ld returned 1 exit status
    gmake[1]: *** [MMCSD_bbbAM335x_EMMC_armTestproject.out] Error 1
    gmake: *** [all] Error 2
    makefile:150: recipe for target 'all' failed

    The compiler is missing a function that should be removed...  But somewhere, something, buried deep in this stuff, someone is still using it.  And now, suddenly, it's not being linked to...  AND NO CHANGES WERE EVEN MADE TO THE LINKER SETTINGS.  OR TO THE CFG FILE.

    This is what I mean...  This has been my life of dealing with this environment for the past 17 months.  One, almost insignificant, alteration to an example, and nothing builds anymore.  And it takes 3 or more days to get an explanation, if you can.

  • Rahul Prabhu said:
    Chris,

    [snip]

    If you are still running into issues, we can provide further guidance on your build issues.

    Regards,
    Rahul

    Rahul,

    Awaiting further guidance...   (while fighting with this environment)

  • Christopher,

    The board library for AM335x platforms links into the following LLD and component libraries for performing platform level initialization:

    • OSAL_LIB = "$(PDK_INSTALL_PATH)/ti/osal/lib/nonos/am335x/a8/release/ti.osal.aa8fg" ( OS abstraction layer )
    • UART_LIB = "$(PDK_INSTALL_PATH)/ti/drv/uart/lib/am335x/a8/release/ti.drv.uart.aa8fg" (UART LLD for logging and STdio)
    • I2C_LIB = "$(PDK_INSTALL_PATH)/ti/drv/i2c/lib/am335x/a8/release/ti.drv.i2c.aa8fg" (I2C driver to read board ID from EEPROM)
    • CSL_LIB = "$(PDK_INSTALL_PATH)/ti/csl/lib/am335x/a8/release/ti.csl.aa8fg" (Register level CSL for PRCM and pinmux)

    these libraries will be linked in depending on options that are used with Board_init in your application. I looked at the MMCSD examples and noticed that the code calls the Board library using the following options:

    Board_initCfg boardCfg;
    board_initGPIO();
    boardCfg = BOARD_INIT_PINMUX_CONFIG | 
               BOARD_INIT_MODULE_CLOCK | BOARD_INIT_UART_STDIO;
    Board_init(boardCfg);

    The last option is the one that brings in the UART logging functionality which is prompting the linker to complain about the missing symbol as you have remove the link to the UART library. If you don`t need the UART LLD in your SD MMC example other than changing the IO_console can you also remove the BOARD_INIT_UART_STDIO from the board library API configuration options.

    Regards,

    Rahul

  • Rahul Prabhu said:

    I looked at the MMCSD examples and noticed that the code calls the Board library using the following options:

    Board_initCfg boardCfg;
    board_initGPIO();
    boardCfg = BOARD_INIT_PINMUX_CONFIG | 
               BOARD_INIT_MODULE_CLOCK | BOARD_INIT_UART_STDIO;
    Board_init(boardCfg);

    The last option is the one that brings in the UART logging functionality which is prompting the linker to complain about the missing symbol

    Nope...

    //CSW    boardCfg = BOARD_INIT_PINMUX_CONFIG |
    //CSW        BOARD_INIT_MODULE_CLOCK | BOARD_INIT_UART_STDIO;
    
        boardCfg = BOARD_INIT_PINMUX_CONFIG |   BOARD_INIT_MODULE_CLOCK ;
        Board_init(boardCfg);

    Still fails to link.  However, if I comment out the "Board_init(...) " call, it does link.  But the system is not initialized.  Clearly "Board_init(...)" is attempting to call this missing function even though it is not supposed to.

    But EVEN WORSE, simply removing "UART_printf" from the COMPILE step causes the LINKER step to fail.

    You state:

    Rahul Prabhu said:

    ... as you have remove the link to the UART library. If you don`t need the UART LLD in your SD MMC example other than changing the IO_console can you also remove the BOARD_INIT_UART_STDIO from the board library API configuration options.

    However, please explain how "I" removed the UART library...?  I made NO CHANGES to anything in the linker settings or to the CFG file.  All I did was comment out "UART_printf"

    To summarize, take the attached example project, (with the BOARD_INIT_UART_STDIO removed) and switch back and forth between 

    #ifndef IO_CONSOLE
    #define MMCSD_log                UART_printf
    //     #define MMCSD_log				DummyLog
    #else

    and 

    #ifndef IO_CONSOLE
    //      #define MMCSD_log                UART_printf
    #define MMCSD_log				DummyLog
    #else

    And it results in 

    bbbAM335x_lld_init.c:(.text.Board_uartStdioInit+0x10): undefined reference to `UART_stdioInit'

    Which cannot be explained.BrokenExampleAgain.zip

  • Any movement on this? Can anyone explain this obscure and unneeded dependency?
  • Chris,

    I was able to reproduce the issue that you have highlighted here. I believe the reason why you are running into an issue seems to be the nature in which GCC links libraries and the way the XDC tools auto generates the linker command files for all the CSL, LLD and board library.  

    Once I changed the order of where the board library is include in the .cfg file the error goes away. Please try the updated .cfg file and let me know if the issue is resolved. On further analysis of Debug/configPkg/linker.cmd, I noticed that if the board library  appears above all dependent LLD drivers then the linker error is not observed but if board library appears after the UART LLD driver then the issue is observed.

    mmcsd_emmc_bbbam335x.cfg

    This occurs because the GCC compiler doesn`t circularly search for library symbols.  It only looks for the symbols from left to right so if you link the uart LLD before board library when it finds the UART_StdioInit symbol in the board, it is unable to locate it in the library linked after board but the linker doesn`t seem to wrap around to recheck for that symbol in libraries linked before.  Hence we recommend that the libraries should be encapsulated with  -Wl,--start-group and -Wl,--end-group when linking using GCC but in this case the configPkg/linker.cmd file is not linked along with other libraries

    Bottom line is that the order in which the libraries are included using .cfg matters when compiling BIOS project with GCC. In make files, you can put the generated linker command file within -Wl,--start-group and -Wl,--end-group  to avoid the issue but in CCS that option can`t seem to be used as that linker command file is considered like a object file.

    Regards,

    Rahul

  • Rahul Prabhu said:

    Once I changed the order of where the board library is include in the .cfg file the error goes away. Please try the updated .cfg file and let me know if the issue is resolved. On further analysis of Debug/configPkg/linker.cmd, I noticed that if the board library  appears above all dependent LLD drivers then the linker error is not observed but if board library appears after the UART LLD driver then the issue is observed.

    In an effort to understand it, I systematically made changes to my file to match yours.  Ultimately, all I had to do was to move 

    var UartPackage = xdc.loadPackage('ti.drv.uart');

    above

    var Board = xdc.loadPackage('ti.board');

    and it linked.  But if I moved it too far up the CFG file, I recieved more linker errors,  they appear to come from CSL. 

    Rahul Prabhu said:

    This occurs because the GCC compiler doesn`t circularly search for library symbols.  It only looks for the symbols from left to right ...  

    This makes sense considering the link order limitation of the the GCC toolset.  I have dealt with this problem before in Linux, but I know what the library dependencies are, and I can adjust my makefile accordingly.  Not so, in this environment...

    Rahul Prabhu said:

    Bottom line is that the order in which the libraries are included using .cfg matters when compiling BIOS project with GCC. In make files, you can put the generated linker command file within -Wl,--start-group and -Wl,--end-group  to avoid the issue but in CCS that option can`t seem to be used as that linker command file is considered like a object file.

    So... we know the problem, we know the solution, but CCS and the build eco-system does not allow us to easily solve it??  The solution is to just "know" which modules must be listed first and manually manipulate the CFG file to handle it?  Then pray that XGCONF does rearrange them on us?

    Where is it documented as to which modules depend on which other modules?  I can't even find useful doc on the modules.  I have to go back to the "unsupported" StarterWare 2.00.01.01 and read that doc and pray I can gleam some useful info from it... Because the new stuff is all Doxygen generated garbage which is unstructured, unseachable, usually unlinked, and devoid of any useful samples.  The best doc I even saw in this environment was the NDK doc...  Very comprehensive.  Nothing like that these days.

    There are over a dozen libraries that are being linked in.  If I just have to guess which order to put them in, that factorials out to millions of combinations.  Even if I limit it to the 6 or so "driver" libs, that's still 720 combinations...

    I'll mark it as solved, because it is.  Plus, using the same technique, it also solved my other thread of pretty much the same issue:

    e2e.ti.com/.../693892

    But any other place would call this a serious deficiency and a hack work around.  Not "solved".

  • Chris,

    I understand the angst that this issue has caused here and have flagged this to CCS team to allow the generated linker command file to be included in the link time option -Wl,--start-group and -Wl, --end-group as it links libraries

    At a high level, we have tried to highlight the dependencies in the stack in the block diagram here:
    processors.wiki.ti.com/.../Processor_SDK_RTOS_Software_Stack

    But board library library has a dependency on UART, I2C and some time PM LLD so I do believe that we need to better document the dependencies for new users. I will work on creating a dependency table for the components.

    Thanks for confirming the fix and for the feedback.

    Regards,
    Rahul
  • Rahul Prabhu said:
    Chris,

    But board library library has a dependency on UART, I2C and some time PM LLD so I do believe that we need to better document the dependencies for new users. I will work on creating a dependency table for the components.

    Rahul,

    You're welcome.  You are one of the few who does eventually give me useful information.  I find it annoying that I have to pester you (personally, or 'you" as in the community) to get answers.  I am usually getting frustrated for a week before I post, and by then I'm rather angered...  The other choice is to post questions the instant I have a problem, and then come across as a troll, and someone who doesn't try to research and solve issues before asking for help.

    As I have said, doc is lacking.  Even that link you posted is to an image which doesn't answer things... as per my other thread... where is "board_init" ?  Which LLD is supplying it?  Why is it needing to link to UART stuff, but apparently not needing to link to I2C stuff?