This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

attribute((at(x)) .bss sections not initialized

In our ASIC, we have multiple cores: a cortex M series, plus a DSP. The separate DSP core is getting it's memory poplulated by it's output elf into several arrays that are located (using the __attribute__((at(x)) method) at the correct shared memory location as seen by the Cortex, and that C file is compiled into the cortex image.

We do this so that uVision can load the DSP's memory as well.

Unfortunately, it seems like the linker trickery used to make this happen doesn't put the sections that should be zero init in the list of things to be initialized by __scatterload_zeroinit (or i.__scatterload_zeroinit).

These .bss-ish sections do end up in the elf file (because our post processing tool that converts the cortex mcu AXF to a flash image knows what to do), but when loading from the debugger all these specifically placed .bss sections (initialized arrays of all zeros) don't end up being initialized by __scatterload during startup.

Any help with this? Is this a keil tool bug? Am I doing it wrong?

Parents
  • What does the scatter file look like, because realistically if the ELF file contains sections defining the void, it's not something the run time code is initializing? The things being initialized need to fall within the scope of the .text (RO) section

    You also could add the appropriate clearing code in your own start up code prior to calling __main, if you expect specific regions to be zeroed at reset.

Reply
  • What does the scatter file look like, because realistically if the ELF file contains sections defining the void, it's not something the run time code is initializing? The things being initialized need to fall within the scope of the .text (RO) section

    You also could add the appropriate clearing code in your own start up code prior to calling __main, if you expect specific regions to be zeroed at reset.

Children
  • __attribute__((section(".void1"))) int somethingvoid1[10240] = { 0 };
    __attribute__((section(".void2"))) int somethingvoid2[20480];
    
    LR_IROM1 0x08020000 0x00020000  {    ; load region size_region
      ER_IROM1 0x08020000 0x00020000  {  ; load address = execution address
       *.o (RESET, +First)
       *(InRoot$$Sections)
       .ANY (+RO)
      }
      RW_IRAM1 0x20000000 0x00018000  {  ; RW data
       .ANY (+RW +ZI)
      }
      VOID1 0xC0000000 0x01000000  {  ; Void 1
      *.o (.void1)
      }
      VOID2 0xD0000000 0x01000000  {  ; Void 2
      *.o (.void2)
      }
      VOID3 0xE0000000 EMPTY 0x01000000  {  ; Void 3 Classic form not zeroed
      }
    }
    

  • LR_IRAM1 0x00008000 0x00020000
    {
        RW_IRAM1 0x00008000 0x0001ff00
            {
            *.o (RESET, +First)
            *(InRoot$$Sections)
            .ANY (+RO)
            .ANY (+RW-CODE)
            .ANY (+RW-DATA)
            .ANY (+ZI)
            }
        RW_IRAM2 +0 0x100
            {
            powerup_structure.o (+RW-DATA)
            }
    }
    


    (all of our code and data is loaded into iRam, located at 0x8000. We have a powerup structure at 128K-256.)

    Is what my current .sct file looks like. The "at" addresses are in the 0x4000_0000 range. I know these sections aren't represented by the .sct file, but the linker hasn't complained so far (The .data-ish sections at 0x4000_xxxx are in the .elf and populated by the debugger. The .bss-ish sections are in the elf, but they're not in the startup list)

    Unfortunately, the size and order and exact location of the "at" sections isn't known until compile time (since they're dictated by the compilation of the DSP code and the compiler doesn't make a single .bss, .data, etc.). I can't rename the sections away from their current autogenerated name (ARM.__AT_0x4000xxxx) without causing the linker to link them properly.

    Similarly, I can't write my own 'zero out' code that runs after startup, because i need to know the addresses of the start and length of the sections to zero out, which again, aren't known until compile time.

    If I create a second section that covers 0x4000_0000 to 0x5000_0000

    LR_IRAM2 0x40000000 0x10000000
    {
        RW_IRAM21 0x40000000 0x10000000
            {
            }
    }
    

    (which all of my external CPU memories are located within), then I end up with this:

    Error: L6971E: quark1.o(.ARM.__AT_0x40131148) type RW incompatible with quark1.o(.ARM.__AT_0x40130000) type ZI in er RW_IRAM21.
    Error: L6971E: quark1.o(.ARM.__AT_0x40132418) type RW incompatible with quark1.o(.ARM.__AT_0x40131400) type ZI in er RW_IRAM21.
    Error: L6971E: quark1.o(.ARM.__AT_0x40141100) type RW incompatible with quark1.o(.ARM.__AT_0x40140000) type ZI in er RW_IRAM21.
    Error: L6971E: quark1.o(.ARM.__AT_0x40142418) type RW incompatible with quark1.o(.ARM.__AT_0x40141400) type ZI in er RW_IRAM21.
    Error: L6971E: quark1.o(.ARM.__AT_0x40150074) type RW incompatible with quark1.o(.ARM.__AT_0x40150000) type ZI in er RW_IRAM21.
    Error: L6971E: quark2.o(.ARM.__AT_0x40231D50) type RW incompatible with quark2.o(.ARM.__AT_0x40230000) type ZI in er RW_IRAM21.
    Error: L6971E: quark2.o(.ARM.__AT_0x40232228) type RW incompatible with quark2.o(.ARM.__AT_0x40232208) type ZI in er RW_IRAM21.
    Error: L6971E: quark2.o(.ARM.__AT_0x40232498) type RW incompatible with quark2.o(.ARM.__AT_0x40232488) type ZI in er RW_IRAM21.
    Error: L6971E: quark2.o(.ARM.__AT_0x402324C4) type RW incompatible with quark2.o(.ARM.__AT_0x402324B4) type ZI in er RW_IRAM21.
    Error: L6971E: quark2.o(.ARM.__AT_0x40232610) type RW incompatible with quark2.o(.ARM.__AT_0x402325EC) type ZI in er RW_IRAM21.
    Error: L6971E: quark2.o(.ARM.__AT_0x40232888) type RW incompatible with quark2.o(.ARM.__AT_0x4023287C) type ZI in er RW_IRAM21.
    Error: L6971E: quark2.o(.ARM.__AT_0x40241D50) type RW incompatible with quark2.o(.ARM.__AT_0x40240000) type ZI in er RW_IRAM21.
    Error: L6971E: quark2.o(.ARM.__AT_0x402423FC) type RW incompatible with quark2.o(.ARM.__AT_0x40242334) type ZI in er RW_IRAM21.
    Error: L6971E: quark2.o(.ARM.__AT_0x4024271C) type RW incompatible with quark2.o(.ARM.__AT_0x40242710) type ZI in er RW_IRAM21.
    Error: L6971E: quark2.o(.ARM.__AT_0x4025033C) type RW incompatible with quark2.o(.ARM.__AT_0x40250000) type ZI in er RW_IRAM21.
    Error: L6971E: quark3.o(.ARM.__AT_0x40321800) type RW incompatible with quark3.o(.ARM.__AT_0x40300200) type ZI in er RW_IRAM21.
    Error: L6971E: quark3.o(.ARM.__AT_0x40325800) type RW incompatible with quark3.o(.ARM.__AT_0x40322880) type ZI in er RW_IRAM21.
    


    and nothing links.

  • Compile time of what? All these things should be known by the time the linker has pulled it all together.

    The DSP code compilation is a separate operation, right? Then you're trying to integrate that object code into some other Cortex-M3 app that payloads it to it's final destination on the DSP.

    Then perhaps your "DSP object to 'C' structure at" translation program needs to do a better job at building tables that tie all this together so processing can be achieved at run-time, or that it acts more like a loader.

  • for reference:

    cortex.elf depends on dsp.o depends on dsp.c depends on dsp.elf depends on a bunch of other files that are irrelevant.

    DSP.C places all the right values at all the right locations in memory via C arrays located using __attribute((at()) (the DSP memory is linearly mapped into cortex memory on the peripheral bus). There is an array for every dsp.elf section with initialized data for every value(either zeros or data)for every word in dsp memory that is referenced by DSP.ELF.

    When the debugger loads the contents of the module DSP.O into memory at load time (should get all .data sections), and __scatterload is performed (should get all .bss/zeroinit sections) then the DSP should be completely populated without any other magic that needs to happen. No fixup, no copying, etc.

    Well, or at least it should be this way. The zero init sections aren't ending up in the linker created list that __scatterload uses, and I can't figure a way to convince the linker to do such a thing.

    It's not super huge, as our production bootloader zeros out the zero init sections because it references the cortex elf (which specifies them), and our debug flow can blanket zero out the DSP memory prior to enabling jtag.

    But it is irritating and seems to be a bug in the keil linker.

  • For your "attribute((at(x)) .bss sections" to stand any chance of being scatter loaded, they are going to need to get into you LR_IRAM1 load region so they get described and tabled for processing. They have to be described in some load region, because the scatter loader is designed to move things, typically unpacking from a rom image into uninitialize ram regions. I'm not sure what you're describing is a bug in the linker, but if it were you'd need to create a worked example and provide that to the support group.

    What's to stop you skipping the whole DSP.ELF -> DSP.C step, and instead merge the .HEX or .ELF for the DSP blobs with the Cortex .HEX or .ELF as a post link step?