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.

Compiler/PROCESSOR-SDK-AM335X: The solution to create an SD card image when using the TI compiler and a BBB

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

Tool/software: TI C/C++ Compiler

Not a question.  I am posting this for posterity, in the event anyone else had this problem, to avoid spending weeks trying to figure it out.

Goal:  Using the TI compiler for a BeagleBone Black, to create an image of the program, which is named "app", and placed on an SD card, to be loaded by the bootloader. 

The link below shows how to build the SD card, load the bootloader, modify your file to be the "app", etc...  But the problem is that these steps don't properly create an app that has the entry point at address 0x80000000, which is required by the MLO bootloader.  That actually needs to happen during the compile and link stage.  And the compile needs to be done twice, as you will see.

processors.wiki.ti.com/.../AM437x

So, after much begging for help, and digging and many failures from older posts, I have it solved.

(Old posts on E2E didn't work. And I suspect, given TI's penchant to change things and break the way things work, this will probably not work for long. But it works now.)

We need to tell the linker to set the address of function _c_int00 to be at location 0x80000000.  The TI compiler along with the entire build environment doesn't make that easy to figure out.  To do that, we need to have a linker script which tells it so.  So we add a "custom.cmd" script to the project at the root level.

In order to figure out what to put in the custom linker script, you need to find out:

1. Where the entry point is

2. What library file provided the entry point.

And this also isn't well documented...  Build your program and look in the MAP file to find out the entry point address.  In my test, it was 80008698.  So, based on the address of 80008698, I looked further down the the map file for that address, and that says what library and object file provided the function.

ENTRY POINT SYMBOL: "_c_int00"  address: 80008698

      800085a0    0000007c     sysbios.aea8fnv : arm_TaskSupport_asm.obj (.text:_ti_sysbios_family_arm_TaskSupport_buildTaskStack)
      8000861c    0000007c     ti.targets.arm.rtsarm.aea8fnv : Assert.oea8fnv (.text:xdc_runtime_Assert_raise__I)
--->> 80008698    00000074     boot.aea8fnv : boot.oea8fnv (.text)
      8000870c    00000074     sysbios.aea8fnv : BIOS.obj (.text:ti_sysbios_family_arm_a8_intcps_Hwi_dispatchFIQC__I)

This would indicate the function came from something called boot.aea8fnv...   Which appears to be an "archive" file (to some of us Window programmers, it's a library file, which we know is just a big blob of object files). So if I am reading the map file correctly, that was pulled from object file boot.oea8fnv.

So, next we have to create the "SECTION" in a custom.cmd file to tell it to load that at address 80000000:

We search the C:\Ti\bios_ww_xx_yy_zz folder for that archive file. Then put the absolute path into the script:

SECTIONS {
    .text:_c_int00 { C:\ti\bios_6_46_05_55\packages\ti\targets\arm\rtsarm\lib\boot.aea8fnv<boot.oea8fnv>(.text) } > 0x80000000
}

Just about every linker script file I've seen seems to have it's own custom syntax, I can only guess at what this is. Other are welcome to add an understanding to this as they want.

.text:_c_int00  - This means into the "text" section, function named _c_int00

{ C:\ti\bios_6_46_05_55\packages\ti\targets\arm\rtsarm\lib\boot.aea8fnv<boot.oea8fnv>(.text) } - This appears to be the library-archive-filename<actual-object-filename>...  But I have no idea what the significance of (.text) is, since it's already at the front of the line... Nor do I know why we need to provide any of this anyway, since the linker knows the function we are linking to.  But it doesn't work without it.

> 0x80000000 - is obviously telling it to put this function at address 80000000

Re-run the build, and verify the entry point where it's supposed to be.

ENTRY POINT SYMBOL: "_c_int00"  address: 80000000
output                                  attributes/
section   page    origin      length       input sections
--------  ----  ----------  ----------   ----------------
.text:_c_int00 
*          0    80000000    0000008c     
                80000000    00000074     boot.aea8fnv : boot.oea8fnv (.text)
                80000074    00000008     rtsv7A8_A_le_n_v3_eabi.lib : args_main.obj (.tramp._args_main.1)

Next, you have to use the tools to create the HEX file, and add the 8 byte header.  But when using the "arm-none-eabi-objcopy.exe" and the "tiimage.exe" programs, you will have to specify the absolute path to those executables, since they are GNU tools, and the environment is pointing to the TI compiler. I simply put this, and ran it on my own command prompt from inside the debug or release directory.

C:\ti\ccsv7\tools\compiler\gcc-arm-none-eabi-6-2017-q1-update\bin\arm-none-eabi-objcopy.exe -O binary TI_BLinkTest.out TI_BLinkTest.bin

C:\ti\pdk_am335x_1_0_7\packages\ti\starterware\tools\ti_image\tiimage.exe 0x80000000 NONE TI_BLinkTest.bin app

Where (in this case) the compiler output file name was "TI_BlinkTest.out" and it generates the file named "app".  Place that on the SD card, and it should boot properly.

If anyone wishes to add information to provide a better understanding, that would be appreciated.

  • You obviously put a lot of work into this.  Thank you!

    I cannot comment on the part at the end where you use tiimage.  I lack expertise on that tool and what it does.  But I can comment on the larger part where you arrange to put the entry point at a fixed address.

    The article Accessing c_int00 is about this situation.  One of the things it says is ...

    As of XDC 3.24.02, this assembly code is placed in .text and not .text:_c_int00. This will be fixed in a future release of XDC and BIOS.

    It is this detail which forces you to figure out exactly which module of which library contains the boot routine.  This was written quite some time ago.  And it is still not fixed.  I can tell by this detail in your first map file ...

    Christopher Weber said:
    --->> 80008698 00000074 boot.aea8fnv : boot.oea8fnv (.text)

    You explain this some in your post.  I'll explain it again, to make it even clearer.  This says the .text input section from the object file boot.oea8fnv, which is from the library boot.aea8fnv, starts at address 0x80008698, and is 0x74 bytes long.  For our purposes, that last .text is the problem.  Because it has the same name as all the other .text input sections, it is difficult to get a handle on it in order to control placement of it.  If instead of .text, this input section were named .text:_c_int00, it would be much easier.  Then you would only have to write ...

        .text:_c_int00 > 0x80000000

    This code says to collect all the input sections named .text:_c_int00 (and there is only one) into an output section that is also named .text:_c_int00.  And allocate that output section to the address 0x80000000.  

    I don't know why XDC and SYS/BIOS have not been changed to make this detail easier.  I'll ask those experts to comment on this thread.

    Throughout this post I have used the terms input section and output section.  Those terms, and other basics of linker command files, are explained in the article Linker Command File Primer.

    Thanks and regards,

    -George

  • George,

    Thanks for the contributing more information.  Now I think I understand why 

     SECTIONS {
       .text:_c_int00 > 0x80000000
     }

    does not work.  Here is along thread, no need to read all of it.  But in one reply I posted that begins "Can you spell this out??  All I am doing it throwing random changes because nothing is specific." lists a few dozen different ways I tried it.  And the next reply where I essentially "stumbled" on the solution on my own (which resulted in my immediate creation of this post in order to help others)

    e2e.ti.com/.../662587

    One of the BIG annoyances is that people just throw around fragments of statements.  As a someone not well practiced in linker scripts (and even more annoyed that the environment obfuscates it from me), I am never sure where to put fragments.  Which is why I spelled out which file, and the text that surrounds the fragment.

    Your statement "This was written quite some time ago.  And it is still not fixed. "  is no surprise.  It's been 5 years!!  I am truly disgusted with their ignoring old, known issues, while busily changing the environment so you can't find things anymore.  I can't tell you how many times I start reading some WiKi and eventually learn that its useless because it's old, outdated, deprecated,...  they've scrapped all of the material and just re-written it in the next "whiz-bang" feature.  Going through "StarterWare 2.0.0 is a classic example...  You can't use any of it in SysBios

    The "Linker Command File Primer" will be a nice read...  even if you can't do anything with the information because the scripts are all autogenerated.

    BTW.  My employer uses the TI compiler on a dozen projects, with hundreds of source code files in each.  They have said they are not interested in investing the time/effort/money to convert all of it to GNU (When I've tried, it always results in a train wreck because the IDE starts changing stuff behind your back).  For that kind of time and effort, just go to another device vendor who has better support.

  • Christopher Weber said:
    The "Linker Command File Primer" will be a nice read...  even if you can't do anything with the information because the scripts are all autogenerated.

    That's inaccurate.  Many of your problems arose from the fact that you were attempting to write linker command file code, but didn't know the details.  This article explains those details.

    Thanks and regards,

    -George

  • George Mock said:
    Christopher Weber
    The "Linker Command File Primer" will be a nice read...  even if you can't do anything with the information because the scripts are all autogenerated.

    Thanks and regards,

    -George

    George,
    Okay, let me re-state it as "even if you can't find anything that clearly explains how to get around the build environment, in order to customize parts of your linker script".
    Because dropping in a *.cmd file, and the environment just uses it as a linker script was something new to me.