Shop OBEX P1 Docs P2 Docs Learn Events
[PropGCC] Symbols clashing when compiled into COG module and CMM/LMM module in the same binary? — Parallax Forums

[PropGCC] Symbols clashing when compiled into COG module and CMM/LMM module in the same binary?

DavidZemonDavidZemon Posts: 2,973
edited 2016-08-20 03:34 in Propeller 1
I can share more specific code, but here's the gist of it:

Main.cpp - This is compiled as CMM or LMM
#include <uart.h>

using namespace PropWare;

int main () {
  UART tx;
  tx.send_array("Hello, world!\n");
  return 0;
}

driver.cogcpp - This is a COG module, compiled with the "-mcog -xc++ -r" flags
#include <uart.h>

using namespace PropWare;

_NATIVE int main () {
  // const UART tx;
}

This code works. I see "Hello, world!" printed at the console.


But if I uncomment the constructor in my cog module...


driver.cogcpp - This is a COG module, compiled with the "-mcog -xc++ -r" flags
#include <uart.h>

using namespace PropWare;

_NATIVE int main () {
  const UART tx;
}

The console no longer shows anything.

If I take the contents of uart.h, which looks something like this:

uart.h
namespace PropWare {
  class UART {
    ...
  };
}

and copy them directly into driver.cogcpp, I get exactly the same results (no real surprises here... I just wanted to be sure.
So now driver.cogcpp looks like this:
namespace PropWare {
  class UART {
    ...
  };
}

using namespace PropWare;

_NATIVE int main () {
  const UART tx;
}

But I can get it working again by changing the symbols. The easiest way to do this was remove the PropWare namespace around the UART definition in driver.cogcpp:
using namespace PropWare;

class UART {
  ...
};

_NATIVE int main () {
  const UART tx;
}

Now, I don't think this should be necessary. I think GCC should be smart enough to recognize that, though these are named the same in source code, the symbols should be different because they are compiled with different memory models. But my tests show that isn't the case. Is this a bug in PropGCC? Maybe better described as a feature request? Or is there something else I'm misunderstanding?

Comments

  • I look forward to hearing of a better solution, but I have a temporary workaround in place:
    #ifdef __PROPELLER_COG__
    #define PropWare PropWare_cog
    #endif
    

    This only work for code within the PropWare namespace though... not good.
  • How are you compiling driver.cogcpp? Generally we recommend running objcopy with --rename-section and --localize-text to rename the .text section and make all the .text symbols local. That'll avoid conflict with functions in the .text section. I *think* it should handle constructors/destructors as well. If it doesn't, then that's a binutils bug.

    If your UART class has static data members though, then there can still be conflicts, and I'm afraid that there's not much we can do there. COG and "regular" code can share data and that's as designed, but if the COG version and non-COG version handle the static data differently then they will conflict.

    Regards,
    Eric
  • Compile cogcpp:
    propeller-elf-gcc     -mcog -xc++ -r -Os -m32bit-doubles -Wall -ffunction-sections -fdata-sections -save-temps --std=gnu++0x -fno-exceptions -fno-rtti -fno-threadsafe-statics <include dirs> -o buffereduartrx.cogcpp.cog buffereduartrx.cogcpp
    propeller-elf-objcopy --localize-text --localize-symbols=PropellerCogLocalizeSymbols.txt --rename-section .text=buffereduartrx.cog buffereduartrx.cog
    
    There's a "magic" step here that isn't show in the CMake output where the .cogcpp.cog file is temporarily renamed to .cog - henceforth the filename mismatch in these two commands.

    PropellerCogLocalizeSymbols.txt contains:
    CNT
    CTRA
    CTRB
    DIRA
    DIRB
    DIRC
    DIRD
    FRQA
    FRQB
    INA
    INB
    OUTA
    OUTB
    PAR
    PHSA
    PHSB
    PINA
    PINB
    PINC
    PIND
    __stack_end
    VCFG
    VSCL
    __clkfreqval
    __clkmodeval
    

    There are static variables on the UART class, but they are all declared const.
    class UART {
        public:
            typedef enum {
                /** No parity */  NO_PARITY,
                /** Even parity */EVEN_PARITY,
                /** Odd parity */ ODD_PARITY
            } Parity;
    
        public:
            static const uint8_t      DEFAULT_DATA_WIDTH     = 8;
            static const UART::Parity DEFAULT_PARITY         = NO_PARITY;
            static const uint8_t      DEFAULT_STOP_BIT_WIDTH = 1;
    
            static const int MAX_BAUD = 4413793
    
  • Hmmm, that's odd... what you're doing *should* work I think. There are a few oddities though:

    (1) The UART class in PropWare looks to be abstractl. I presume you're sub-classing it in your application. Are you doing that the same way in the COG and non-COG code?

    (2) The send_array function is marked as HUBTEXT. Why is that? I'm wondering if that might somehow be confusing things.

    (3) Does the same class work if you include it twice in non-COG code?

    The odd thing is that if a definition in the COG and non-COG code were conflicting, I would expect a linker error instead of the code failing to work.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2016-08-21 02:15
    Clearly its time to move away from my simple abstracted code above and onto the real thing.

    I'm working in the PropWare_BufferedUART example:
    https://github.com/parallaxinc/PropWare/tree/develop/Examples/PropWare_BufferedUART
    As I mentioned though, I was able to get it working by providing the macro "#define PropWare PropWare_cog", so the real code is not as simple as my original snippets at the top anymore.

    Now that you can see the exact code I'm working with, I'll answer your questions:

    1) Yes - both are in fact using the UARTTX and UARTRX classes. The only difference is that I have the following macros at the top of uart.h for better size optimizations:
    #ifdef __PROPELLER_COG__
    #define virtual
    #endif
    

    2) No idea why I had send_array declared as HUBTEXT in the old 2.x release. It's gone in the develop branch.

    3) I know I can have two UART instances, one UARTTX and one UARTRX. I don't know that I've ever tried to have two UARTTX instances.

    To reproduce on a Linux box:
    git clone --recursive git@github.com:parallaxinc/PropWare.git
    cd PropWare
    mkdir bin
    cd bin
    cmake ..
    make debug-BufferedUART_Demo
    
    This assumes:
    git, cmake 3.3+ and GNU Make are available on PATH
    PropGCC is extracted to /opt/parallax.
    A Propeller is plugged into your computer and can be found by propeller-load.

    If PropGCC is installed somewhere else, use "cmake -DPROPGCC_PREFIX=<whatever> .." instead of "cmake .."
    The above should program the prop's RAM and begin a simple interactive program. You'll then need to remove my fix by finding the four files where it was applied and removing it:
    david@balrog:~/PropWare/bin$ grep PropWare_cog ../PropWare/* -r
    ../PropWare/hmi/output/printcapable.h:#define PropWare PropWare_cog
    ../PropWare/hmi/input/scancapable.h:#define PropWare PropWare_cog
    ../PropWare/PropWare.h:#define PropWare PropWare_cog
    ../PropWare/utility/queue.h:#define PropWare PropWare_cog
    

    Then running the "make clean debug-BufferedUARTRX_Demo" command again (be sure to run the clean target... I just found a bug with the cog drivers not rebuilding when headers change).

    --Edit--
    feature/14 branch has been merged into develop and deleted. Post edited to reflect this change.
  • I think we're being bitten by https://gcc.gnu.org/onlinedocs/gcc/Vague-Linkage.html. It looks like some inline functions (e.g. PropWare::UART::set_stop_bit_mask) are being compiled into functions and called. This is probably due to the -Os compiler option -- those functions take up substantial space, so the compiler doesn't want to emit them more than once. However, due to the Vague Linkage requirement the symbols are marked as Weak, and hence aren't being caught by --localize-text. At link time the linker grabs one of the definitions from the COG and non-COG and uses it for both :(.

    I'm not sure if this is a bug, exactly, but it's certainly awkward. For now your work-around is probably the best solution.

    Regards,
    Eric
  • That's too bad :(. I'll continue with my workaround I suppose.
Sign In or Register to comment.