can linker symbols be defined in C?

Discussion in 'C Programming' started by Ralph Doncaster, Apr 28, 2014.

  1. I want to define linker symbols in C. I can do it using gcc inline assembler:
    #define STR1(x) #x
    #define STR(x) STR1(x)
    .... more macros that calculate TXDELAYCOUNT
    asm(".global TXDELAY" );
    asm(".equ TXDELAY, " STR(TXDELAYCOUNT) );

    Is there a way to do the same thing in standard C11?
    Ralph Doncaster, Apr 28, 2014
    1. Advertisements

  2. Ralph Doncaster

    James Kuyper Guest

    The only way that standard C provides for defining symbols that are
    meaningful to the linker is by defining identifiers for objects or
    functions with external linkage; C2011 doesn't change that.
    James Kuyper, Apr 28, 2014
    1. Advertisements

  3. No. The C standards don't even explicitly acknowledge the existence
    of a linker (references to "compiliation units" are the nearest
    you get), never mind providing a method of providing what are
    inevitably platform-specific directions to it.
    Andrew Smallshaw, Apr 28, 2014
  4. In fact the C standard does describe linking, though it doesn't refer to
    a "linker" as the tool that does it.

    N1570 describes linking as the 8th and final translation phase:

    All external object and function references are resolved. Library
    components are linked to satisfy external references to functions
    and objects not defined in the current translation. All such
    translator output is collected into a program image which
    contains information needed for execution in its execution

    But you're correct that the C standard doesn't provide a way to define
    linker symbols.
    Keith Thompson, Apr 28, 2014
  5. Ralph Doncaster

    James Kuyper Guest

    On 04/28/2014 05:17 PM, Andrew Smallshaw wrote:
    The standard mentions linkers in footnote 71 (n1570.pdf): "On systems in
    which linkers cannot accept extended characters, an encoding of the
    universal character name may be used in forming valid external
    identifiers.". This is a non-normative footnote, and describes a very
    specific special case, so it doesn't count for much.

    "The separate translation units of a program communicate by (for
    example) calls to functions whose identifiers have external
    linkage, manipulation of objects whose identifiers have external linkage
    .... Translation units may be separately translated and then later linked
    to produce an executable program." (

    The standard does not require that a separate program handle that
    process. However, if such a program is used, it seems to me to be
    reasonable to use the term "linker" to refer to it. I think it still
    makes sense to describe the part of the implementation that handles
    linking together translation units as the "linker", even if it isn't
    actually a separate program.

    "In the set of translation units and libraries that constitutes an
    entire program, each declaration of a particular identifier with
    external linkage denotes the same object or function." (6.2.2p2)

    Those three citations seems to me to be more than enough to qualify as
    "explicitly acknowledging the existence of a linker". They don't do much
    more than acknowledging it, and there's not much more in the rest of the
    standard about linking. The rules about how external linkage works imply
    some constraints on how a linker could be implemented, but no details
    are given.
    James Kuyper, Apr 28, 2014
  6. Ralph Doncaster

    jacob navia Guest

    Le 28/04/2014 22:53, Ralph Doncaster a écrit :
    hi ralph

    What about


    if the macros expand into a character string (with quotes).

    If the macros expand into an integer you do


    In general the compiler emits a .globl for each global name.


    In C you can do this ONCE. Once you have set the value to something you
    can't change it duringthe compilation.

    For instance this is NOT ALLOWED:

    int TXDELAY = 56;

    .... some code ...

    int TXDELAY 967;

    This is NOT allowed in C, but allowed in the gcc assembler! BEWARE.

    If you only set TXDELAY ONCE you can write it in C. If you change it
    several times in the program you can't do that in C and you should stick
    to inline assembly.


    Is it good software practice to do that?

    Do YOU really know what value is used for TXDELAY after 6 changes in the

    The usage of .equ in this form is really a hack. Try to use different
    identifier and stick to C.

    You CAN do the same using the preprocessor however.

    #define TXDELAY 25
    .... code ...
    #undef TXDELAY

    #define TXDELAY 250
    .... code
    #undef TXDELAY

    etc. But that is as a bad hack as asm(".equ ...");

    Note that TXDELAY goes into the executable as a global variable and the
    value stored into the variable is the LAST value used. Did you know that?

    Is THAT really what you want?


    P.S. Sorry for all the guys citing the C standard. They can't do
    anything else. But not all people here are like that.
    jacob navia, Apr 28, 2014
  7. (snip)
    The Linkers I am used to also don't describe "linker symbols" but
    instead "external symbols".

    (I suppose linker symbols could be names for the symbols inside
    the linker, that is, in the linker source program. Most often,
    one can ignore them.)

    C does provide ways to generate external symbols.

    -- glen
    glen herrmannsfeldt, Apr 29, 2014
  8. You're spamming! You're in every thread!
    Bill Cunningham, Apr 29, 2014
  9. Ralph Doncaster

    Ian Collins Guest

    Nice :)

    Some people don't live in the real world.
    Ian Collins, Apr 29, 2014
  10. Ralph Doncaster

    Siri Crews Guest

    No. You can use C as an interpretted language that runs out of the parser with
    no compilation or linking.

    You can do it in most implementations that use a linker (like the unix ld) with
    a linker directive to equate an external symbol to an absolute address.

    extern int externalsymbol;
    static int externalvalue = (intptr_t)&externalsymbol;
    Siri Crews, Apr 29, 2014
  11. Ralph Doncaster

    Kaz Kylheku Guest

    Okay, so here we calculate a name somehow (perhaps based on some
    platform configuration preprocessor symbols) and make TXDELAY
    and alias for that symbol.

    There are less direct ways to do that, which are very portable. E.g.

    /* header */
    extern delay_t *tx_delay_loc;
    #define tx_delay (*tx_delay_loc)

    /* platform-specific .c file */
    delay_t *tx_delay_loc = <platform specific value>;

    Or, if it can't be statically determined, the module init routine
    could do it:

    void board_init(void)
    tx_delay_loc = <whatever>;

    If the location is simple constant memory address, it can be something like:

    #define tx_delay_loc_inline = ((unsigned long *) SUCH_AND_SUCH_TX_DELAY_REG)
    #elif CONFIG_OTHER

    #define tx_delay (*tx_delay_loc_inline)

    These techniques are not incompatible with doing it using toolchain-specific
    linker tricks also, on some of the targets where that is an option.

    In C++ you can abuse a reference to create an alias:

    static delay_t &tx_delay = *tx_delay_loc_inline;

    Or, perhaps, not abuse them at all:

    /* assuming Such and Such platform has a declared SUCH_AND_SUC_TX_DELAY
    as a global variable of type long */
    static long &tx_delay = SUCH_AND_SUCH_TX_DELAY;

    I.e. C++ references at file scope de facto provide a similar capability to
    linker-level symbol aliasing (at least for objects, not functions).
    Kaz Kylheku, Apr 29, 2014
  12. I haven't tried the code, but it looks like it's going to create global variable, i.e. that gets initialized in the bss. The asm code I showed doesn't take any space at runtime. The target platform code I've written in AVR assembler, and gets substituted into a "ldi register, TXDELAY" instruction.If I used a global variable it would get initialized in gcc's __do_copy_data, and I'd have to use the ld instruction instead of ldi.
    I need it to be defined as a global symbol. My soft uart asm code gets compiled to a .o, and then linked with the main.o where the timing values (based on baud rate and CPU clock) are defined.
    I tried:
    const unsigned char &val = 42;
    with g++, and val doesn't show up in the symbol table when I run nm.

    Given everyone else's posts it looks like there's no way to do what I want in a completely portable way, so I'll stick with the few asm statements.
    Ralph Doncaster, Apr 29, 2014
  13. If you mean gcc linker scripts, I've never used them before. It sounds like more work than the asm statements, and still doesn't make it portable.
    Ralph Doncaster, Apr 29, 2014
  14. Yes, that is exactly what I want, and it's only defined once (in my header file).
    The defined values are used in my asm file:

    My previous solution involved adding an extra parameter to TxByte and 2 extra parameters to RxByte which contained the timing values. Having them defined linker symbols is much cleaner (smaller code size, and more readable).
    Ralph Doncaster, Apr 29, 2014
  15. Ralph Doncaster

    Kaz Kylheku Guest

    I was about to say that you can have your assembly sources preprocessed
    in GNU toolchains, but there you go.

    Why don't you do the above stuff with TXDELAYCOUNT in the .S file?

    Then you don't need the STR() hack, because you're not dealing with
    inline assembler.
    Kaz Kylheku, Apr 29, 2014
  16. Ralph Doncaster

    Noob Guest

    Try also asking in comp.arch.embedded, you might get a few useful
    suggestions. Regards.
    Noob, Apr 29, 2014
  17. So it's easier for other people to use with their code. BBUart.S and BBUart.h don't get changed - the user just defines BAUD_RATE (if they want something other than 57600), and includes BBUart.h in their .c file.
    Ralph Doncaster, Apr 30, 2014
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.