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.

PROCESSOR-SDK-AM57X: App fails from SD card

Part Number: PROCESSOR-SDK-AM57X

Hello.

I'm using the IDK AM572x evaluation board.

I'm starting to write & debug my TI-RTOS application on Cortex A15 core (single-core mode only).

When I upload my firmware using the on-board debugger, all works correctly.

But if I use AM57xImageGen.sh script from pdk_.../packages/ti/boot/sbl/tools/scripts/ with next app loading using SD card, processor calls exit() function.

When I investigated that problem, I detected that my program uses .ARM.exidx section, that generates by GCC compiler. That section has existed in project.out file with the required data.

But with AM57xImageGen.sh script loses that section (I cannot find data from it in project.out.rprc file, but section .rodata, for example, exists).

That conversion was made by out2rprc tool, that is provided in SDK without source codes.

How can I add .ARM.exidx section in my project.out.rprc file to get all the required info to load from SD card?

With regards,
Alex

P.S. My working environment is Ubuntu 16.04.6 LTS x64 with CCS 9.1.0, TI-RTOS SDK 06.00, arm-none-eabi-gcc 7.2.1

  • Hi Alex,

    I need to consult internally to understand why .ARM.exidx  might not be included in the RPRC file.

    I have a few questions for you while I'm pursuing this further:

    1. Where does your application exit()? How do you know this is the result of the missing section?
    2. Do you know why this section is being included in your code? Have you investigated the possibility of removing the section from your code using GCC compiler or linker options? From what I can determine by quickly poking around on the web, this section is used for C++ exception handling & debug.

    Regards,
    Frank

  • Hello, Frank

    Yes, you are right. I need this section for C++ exception handling.

    1) It calls exit() because of calling std::terminate(), that is generated inside throw call and is called if exception handler was not found.

    2) This section is being included in my code because I need to handle C++ exceptions.

    I linked my code to full versions of newlib libc and libstdc++. The code running under the debug probe confirmed that.

    With regards,
    Alex

  • Alex,

    Thanks for the feedback. I'm still checking internally about why .ARM.exidx isn't being included in your RPRC output file.

    Where is .ARM.exidx located in your memory map? Are there any other sections located in the same memory region?

    Thanks and regards,
    Frank

  • Alex,

    I'm unclear on how C++ exception handling maps to the requirement for this section. A colleague suggested trying the -fno-exceptions and/or -fno-unwind-tables compiler options to see if this removes the section from the map file. Have you tried these options?

    Can you try including the .ARM.exidx section in a dummy section in the linker command file? I'm wondering if the RPRC tool would then include the section in the output file.

    Regards,

    Frank

  • Frank,

    .ARM.exidx located in RAM (DDR).

    As I see in Debug/configPkg/linker.cmd, that section located in REGION_ARM_EXIDX, that is alias for HOST_PROG (usual main region, where bss, data & other are located).

    If I add a -fno-exceptions flag for compiling, I receive a compilation error: "exception handling disabled, use -fexceptions to enable". That's bad, because I need throw usage.

    -fno-unwind-tables compiler flag doesn't remove my section from map file.

    As I understand you, I reproduce that in almost empty project. Nothing was changed.

    With regards,
    Alex

  • Alex,

    Ok, my understanding from you is that the -fno-exceptions and -fno-unwind-tables compiler options didn't help.

    Can you please try including the .ARM.exidx section in a dummy section along with another section which is being properly included in the RPTC file? For example, create a "user" linker command file which only allocates sections to memory, and which includes something like the following:

    .dummySection :
    {
        *(.data)
        *(.ARM.exidx)

    } > COMMON_DDR3

    In this case, the .data section is being combined with .ARM.exidx into the dummy section named ".dummySection", and this dummy section is being allocated to a memory region named "COMMON_DDR3".

    The user linker command file will be used by linker along with the generated linker.cmd file. GCC on the command line will include two linker command files, which will look something like this:

    -Wl,-T"configPkg/linker.cmd" -Wl,--start-group -Wl,-T"user_linker.cmd" 

     

    Regards, 
    Frank 

  • Frank,

    I tried to include dummy_section.cmd in my project with content, that you advised. But it broke my project compilation with messages like:

    • relocation truncated to fit: R_ARM_PREL31 against `.text'
    • .dummySection has both ordered [`.ARM.exidx' in /home/alex/ti/ccs910/ccs/tools/compiler/gcc-arm-none-eabi-7-2017-q4-major/bin/../lib/gcc/arm-none-eabi/7.2.1/hard/libgcc.a(_udivmoddi4.o)] and unordered [`.data' in /home/alex/ti/ti-processor-sdk-rtos-am57xx-evm-05.03.00.07-Linux-x86-Install/bios_6_75_02_00/packages/gnu/targets/arm/libs/install-native/arm-none-eabi/lib/hard/libg.a(lib_a-syswrite.o)] sections

    If you want to test compilation by yourself, you can use that minimalistic project to reproduce that bug:

    newlib_issue.zip

    If I load firmware from the debugger, all work good (I'm looping on while(1); row).

    If I start that firmware from SDCard and then connect to board with the debugger, processor locates in exit(); call.

    Also, you can use the ROV Classic LoggerBuff module to see required 4 warning messages, if all was good:

    • Inside test
    • Inside try
    • In catch
    • After catch

    With regards,
    Alex

  • Alex,

    Thank for sharing the example code. I'll try the compilation myself and get back with you.

    Regards,
    Frank

  • Alex,

    I verified the .ARM.exidx section isn't included in the RPRC file. I tried various linker options to include this section, but so far I haven't been successful.

    My next step is to verify .ARM.exidx is required for proper operation of your example code. I won't be able to do that until later in the week since I don't currently have access to an AM572x IDK (TI South Campus in Dallas is closed 'till tomorrow due to storm damage).

    Regards,
    Frank

  • Frank,

    As I see, almost one week was passed.

    Do you have some news about that problem?

    With regards,
    Alex

  • Hi Alex,

    Yes, I have an update for you. I was able to verify .ARM.exidx is required for proper operation of your example code. First I checked the behavior of the program on AM547x A15_0 when loaded from JTAG and when loaded using SBL:

    1. When loading A15_0 via JTAG. I see the log sequence you mention above, i.e. Inside test, Inside try, In catch, After catch.
    2. When loading using SBL, I only observe Inside test, Inside try, and then the program aborts.

    Next I added a "go ahead" wait loop at the top of your main() function and performed the experiments described below.

    // FL: add
    volatile uint32_t gGoAhead=0;

    int main() {

        // FL: add
        while (gGoAhead==0)
        {
            ;
        }

        TestException();

        while(1);
    }

    Experiment #1: Load .out file to A15_0 over JTAG, manually clear .ARM.exidx section. In this case, the program behaves the same way as when loading using SBL.

    Experiment #2: Load .out file using SBL. Connect to A15_0 (no GEL file), and manually load .ARM.exidx section (saved during Experiment #1). In this case, the program behaves the same way as when loading from JTAG.

     

    My next step is to review these findings with the SBL developer. I'll also reach out internally to GCC experts to see if there is a way to force the .ARM.exidx section to be included in the RPRC file.

    Thanks a lot for your patience on this issue.

    Regards,
    Frank

  • Accidentally hit the "resolved button".

  • Hi Alex,

    I tried one more experiment where I manually added the .ARM.exidx section to the RPRC file. In this case the example app operates correctly when booted from SBL.

    I've filed a bug for this issue.

    I don't yet have a workaround.

    Regards,
    Frank

  • Frank,

    The actual problem is in out2rprc tool. When it consider if section goes to RPRC file it seems to copy only sections of type SHT_PROGBITS, but .ARM.exidx have type SHT_TI_UNWIND. As a workaround I tried to write script based on objcopy utility to cut the .ARM.exidx and return it to .out file with the same load parameters but with the type SHT_PROGBITS, but all my tries are failed.

    Regards,
    Alexander

  • Alex,

    Thanks for the additional feedback. I'll add this information to the bug report.

    Regards,
    Frank

  • Alex,

    I reached out internally to one of our compiler experts to try to find a workaround using the linker command file, but we weren't successful.

    Unfortunately this looks like a bug in the out2rprc tool. As I said before, I've filed a bug report. However, it isn't clear when the bug will be fixed.

    A colleague suggested another workaround would be to include the .ARM.exidx as another static data section in the application, and then add code at the beginning of main() to copy this section from its load-time to its run-time address. Of course this is only practical if the .ARM.exidx section contents doesn't change after adding the required C++ exception handling functionality.

    Your approach of using objcopy sounds promising. I hope you can get that working.

    Regards,
    Frank

  • I cranked out a sample perl script that will patch the elf binary to force the exidx section to be set to type "PROGBITS" which seems to make out2rprc fill in the section in the converted image (seen by diffing a hexdump of resulting *.rprc.  I tried to do this in a way thats obviously portable to any language like C.  It patches the existing *.out in place, so make a copy before experimenting.

    #!/usr/bin/perl
    use strict 'vars';
    
    die "Syntax: $0 elfile.out\n" if ($#ARGV != 0);
    
    my ($elfFile) = @ARGV;
    
    open FILE, "+<$elfFile" or die "Can't open $elfFile\n";
    binmode FILE or die "Can't binmode\n";
    
    # Check magic
    die "$elfFile not elf\n" if (read32(0) != 0x464c457f);
    
    # Find section table and names
    my $sect_off   = read32(0x20);
    my $sect_ents  = read16(0x30);
    my $string_idx = read16(0x32);
    
    # Find string table
    my $string_sect_hdr = $string_idx * 0x28 + $sect_off;
    my $string_off = read32($string_sect_hdr + 0x10);
    
    # Find a section named ".ARM.extab";
    for (my $i = 0; $i < $sect_ents; $i++) {
    	my $sectoffset = 0x28 * $i + $sect_off;
    	my $nameoffset = $string_off + read32 ($sectoffset);
    	my $name = readasciiz($nameoffset);
    	print "Section $i: $name\n";
    	if ($name eq ".ARM.exidx") {
    		my $type = read32($sectoffset + 4);
    		if ($type == 0x70000001) {
    			# Change it to 1
    			write32($sectoffset + 4, 0x00000001);
    			# Check it
    			if (read32($sectoffset + 4) == 0x00000001)
    			{
    				print "Successfully patched type to PROGBITS\n";
    				exit(0);
    			} else {
    				die "Type write failed\n";
    			}
    		} else {
    			printf "Found unexpected type 0x%08x\n", $type;
    			die "Failure\n";
    		}
    	}
    }
    
    # Read 32 bits binary little endian at specific offset
    sub read32 {
    	my ($offset) = @_;
    
    	seek FILE, $offset, SEEK_SET or die "Can't seek $offset\n";
    
    	my (@val);
    
    	push @val, ord getc FILE;
    	push @val, ord getc FILE;
    	push @val, ord getc FILE;
    	push @val, ord getc FILE;
    
    	return ($val[3] << 24) | ($val[2] << 16) | ($val[1] << 8) | $val[0];
    }
    
    # Write 32 bits binary little endian at specific offset
    sub write32 {
    	my ($offset, $val) = @_;
    
    	seek FILE, $offset, SEEK_SET or die "Can't seek $offset\n";
    
    	my ($bytes);
    
    	# write little endian one byte at a time
    	print FILE chr(($val      ) & 0xff);
    	print FILE chr(($val >>  8) & 0xff);
    	print FILE chr(($val >> 16) & 0xff);
    	print FILE chr(($val >> 24) & 0xff);
    }
    
    # Read 16 bits binary little endian at specific offset
    sub read16 {
    	my ($offset) = @_;
    
    	seek FILE, $offset, SEEK_SET or die "Can't seek $offset\n";
    
    	my (@val);
    
    	push @val, ord getc FILE;
    	push @val, ord getc FILE;
    
    	return ($val[1] << 8) | $val[0];
    }
    
    # Read an ASCIIZ at offset
    sub readasciiz {
    	my ($offset) = @_;
    
    	seek FILE, $offset, SEEK_SET or die "Can't seek $offset\n";
    
    	my (@vals, $val);
    
    	do {
    		my $valc = getc FILE;
    		$val = ord $valc; # turn into a number
    		push @vals, $valc if ($val);
    	} while ($val);
    
    	return join ("", @vals);
    }
    

  • Hello John,

    Sorry for a long answer.

    Thanks for your script, it is very helpful.

    Also, please, fix that issue in the next SDK release (in out2rprc tool). Thanks.

    With regards,
    Alex