EmbDev.net

Forum: ARM programming with GCC/GNU tools Sharing Header files between C and Assembly (enum support)


Author: Tat Wan (Company: Universiti Sains Malaysia) (tcwan)
Posted on:

Rate this post
0 useful
not useful
Hi,

I'm interested in (re)writing a bunch of drivers for a project in 
assembly, which will be called from C routines. The Compiler and 
Assembler are GNU gcc and as.

I plan to run the Assembly language files through the C pre-processor 
before actual assembly, so that a single header file can be shared 
between the assembly driver routines and the C interface to the routine.

However, I'm having a problem trying to find a good and clean approach 
for dealing with enums. Is there a way to define enums such that they 
can be referenced correctly in both Assembly and C, without duplicating 
it manually like in the following code fragment.
#ifndef __ASSEMBLY___ 
typedef enum { ENUM_A, ENUM_B, ... } enumvalues;
#else 

#define ENUM_A 0
#define ENUM_B 1
...

#endif

TIA

Author: Jörg Wunsch (dl8dtl) (Moderator)
Posted on:
Attached files:

Rate this post
0 useful
not useful
No, there's no better way than that.  enums are a C language construct,
so they cannot be handled by an assembler.

I hacked a short Perl script that can automatically extract all enum
values from the stabs debugging information (-gstabs) of your object
file(s) (including the final ELF file), and return it as a sequence
of #define statements.  So you could use that to construct an
assembler-only include file supplying #define macros that match the
C file's enum values.

Author: Bartli (Guest)
Posted on:

Rate this post
0 useful
not useful
Perhaps something like this?
#ifdef __ASSEMBLY__
#define BEGIN_ENUM
#define ENUM_VAL(name, value) .equ name, value
#define END_ENUM(enum_name)
#else
#define BEGIN_ENUM typedef enum {
#define ENUM_VAL(name, value) name = value,
#define END_ENUM(enum_name) } enum_name;
#endif


BEGIN_ENUM
ENUM_VAL(A, 0)
ENUM_VAL(B, 1)
END_ENUM(foo)

Author: Bartli (Guest)
Posted on:

Rate this post
0 useful
not useful
Depending on your target CPU .equ's syntax may differ, refer to the gas 
manual. Also you might want to use .equiv instead of .equ, again, refer 
to the gas manual.

Author: Tat Wan (Company: Universiti Sains Malaysia) (tcwan)
Posted on:

Rate this post
0 useful
not useful
Thanks for all the suggestions. I prefer Bartli's approach since it's 
done in a single pass. I suppose having to manually specify the enum 
value each time is a minor tradeoff.

Author: Jörg Wunsch (dl8dtl) (Moderator)
Posted on:

Rate this post
0 useful
not useful
You have to be careful though to not specify two names for the
same value.   This is perfectly legal for a C enum, but probably
rather not what you intend.

Author: Bartli (Guest)
Posted on:

Rate this post
0 useful
not useful
Yes...on second thought I'd think twice before using my approach because 
it leaves you no choice but to assign every value manually.

Personally before I go and parse debug information to generate code I'd 
probably rather invent an own small DSL (using an existing scripting 
language, of course) and use that to define my data and have the C 
headers and the assembly source generated from it.

Author: Bartli (Guest)
Posted on:

Rate this post
0 useful
not useful
This is fun. Here's a version that doesn't require you to assign the 
values manually. You could easily extend this to provide full C enum 
support where the values optionally may be assigned.

#ifdef __ASSEMBLY__
#define BEGIN_ENUM .set last_enum_value, 0
.macro enum_val name
.equiv \name, last_enum_value
.set last_enum_value, last_enum_value + 1
.endm
#define END_ENUM(name)
#define ENUM_VAL(name) enum_val name
#else
#define BEGIN_ENUM typedef enum {
#define END_ENUM(name) } name;
#define ENUM_VAL(name) name,
#endif

BEGIN_ENUM
ENUM_VAL(A)
ENUM_VAL(B)
ENUM_VAL(C)
END_ENUM(foo)

Author: Tat Wan (Company: Universiti Sains Malaysia) (tcwan)
Posted on:

Rate this post
0 useful
not useful
I've combined the two versions (to include assignment of values to 
enums), and renamed BEGIN_ENUM/END_ENUM to ENUM_BEGIN/ENUM_END for 
aesthetic reasons. In addition, I've put the macro definition outside of 
the #define ENUM_BEGIN since I'm not sure what happens if multiple 
ENUM_BEGINs are used (where the macro definition would be repeated).

Posted here for easy 'cut-n-paste'
#ifdef __ASSEMBLY__


  .set last_enum_value, 0
  .macro enum_val name
  .equiv \name, last_enum_value
  .set last_enum_value, last_enum_value + 1
  .endm

#define ENUM_BEGIN  .set last_enum_value, 0

#define ENUM_VAL(name) enum_val name
#define ENUM_VALASSIGN(name, value)            \
  .set last_enum_value, value                 ;\
  enum_val name
#define ENUM_END(enum_name)

#else

#define ENUM_BEGIN typedef enum {
#define ENUM_VAL(name) name,
#define ENUM_VALASSIGN(name, value) name = value,
#define ENUM_END(enum_name) } enum_name;

#endif

Author: Bartli (Guest)
Posted on:

Rate this post
0 useful
not useful
Cool. I actually didn't know you could use semicolons as line breaking 
character in gas, that's why I introduced the gas macro enum_value in 
the first place.

Author: Jörg Wunsch (dl8dtl) (Moderator)
Posted on:

Rate this post
0 useful
not useful
Bartli wrote:
> Cool. I actually didn't know you could use semicolons as line breaking
> character in gas, ...

It's processor-dependent.  IIRC, the AVR uses semicolons as a comment
delimiter, and then offers dollar signs as alternate line breaking
characters instead.

Reply

Entering an e-mail address is optional. If you want to receive reply notifications by e-mail, please log in.

Rules — please read before posting

  • Post long source code as attachment, not in the text
  • Posting advertisements is forbidden.

Formatting options

  • [c]C code[/c]
  • [avrasm]AVR assembler code[/avrasm]
  • [code]code in other languages, ASCII drawings[/code]
  • [math]formula (LaTeX syntax)[/math]




Bild automatisch verkleinern, falls nötig
Note: the original post is older than 6 months. Please don't ask any new questions in this thread, but start a new one.