can linker symbols be defined in C?

R

Ralph Doncaster

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?
 
J

James Kuyper

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?

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.
 
A

Andrew Smallshaw

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?

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.
 
K

Keith Thompson

Andrew Smallshaw said:
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.

In fact the C standard does describe linking, though it doesn't refer to
a "linker" as the tool that does it.

N1570 5.1.1.2 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
environment.

But you're correct that the C standard doesn't provide a way to define
linker symbols.
 
J

James Kuyper

On 04/28/2014 05:17 PM, Andrew Smallshaw wrote:
....
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.

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." (5.1.1.1p1)

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.
 
J

jacob navia

Le 28/04/2014 22:53, Ralph Doncaster a écrit :
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?
hi ralph

What about

char *TXDELAY = STR(TXDELAYCOUNT);

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

If the macros expand into an integer you do

int TXDELAY = STR(TXDELAYCOUNT);

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

THE CATCH
---------

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.

BUT

Is it good software practice to do that?

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

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?

jacob

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.
 
G

glen herrmannsfeldt

(snip)
In fact the C standard does describe linking, though it doesn't refer to
a "linker" as the tool that does it.
N1570 5.1.1.2 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
environment.
But you're correct that the C standard doesn't provide a way to define
linker symbols.

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
 
B

Bill Cunningham

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

What about

char *TXDELAY = STR(TXDELAYCOUNT);

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

If the macros expand into an integer you do

int TXDELAY = STR(TXDELAYCOUNT);

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

THE CATCH
---------

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.

BUT

Is it good software practice to do that?

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

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?

jacob

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.

You're spamming! You're in every thread!
 
I

Ian Collins

jacob said:
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.

Nice :)

Some people don't live in the real world.
 
S

Siri Crews

Ralph Doncaster said:
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?

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;
 
K

Kaz Kylheku

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) );

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:

#if CONFIG_SUCH_AND_SUCH
#define tx_delay_loc_inline = ((unsigned long *) SUCH_AND_SUCH_TX_DELAY_REG)
#elif CONFIG_OTHER
...
#endif

#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:

#if CONFIG_SUCH_AND_SUCH
/* 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;
#endif

I.e. C++ references at file scope de facto provide a similar capability to
linker-level symbol aliasing (at least for objects, not functions).
 
R

Ralph Doncaster

/* 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>;

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.
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:



#if CONFIG_SUCH_AND_SUCH

/* 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;

#endif



I.e. C++ references at file scope de facto provide a similar capability to

linker-level symbol aliasing (at least for objects, not functions).

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.
 
R

Ralph Doncaster

Ralph Doncaster wrote:











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;

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.
 
R

Ralph Doncaster

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







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?

Yes, that is exactly what I want, and it's only defined once (in my header file).
http://code.google.com/p/nerdralph/source/browse/trunk/avr/BBUart.h
The defined values are used in my asm file:
http://code.google.com/p/nerdralph/source/browse/trunk/avr/BBUart.S

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).
 
K

Kaz Kylheku

Yes, that is exactly what I want, and it's only defined once (in my header file).
http://code.google.com/p/nerdralph/source/browse/trunk/avr/BBUart.h
The defined values are used in my asm file:
http://code.google.com/p/nerdralph/source/browse/trunk/avr/BBUart.S

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.
 
N

Noob

Ralph said:
Yes, that is exactly what I want, and it's only defined once (in my header file).
http://code.google.com/p/nerdralph/source/browse/trunk/avr/BBUart.h
The defined values are used in my asm file:
http://code.google.com/p/nerdralph/source/browse/trunk/avr/BBUart.S

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).

Try also asking in comp.arch.embedded, you might get a few useful
suggestions. Regards.
 
R

Ralph Doncaster

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.

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.
 

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. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,733
Messages
2,569,439
Members
44,829
Latest member
PIXThurman

Latest Threads

Top