Sharing Header files between C and Assembly (enum support)

OP (Company: Universiti Sains Malaysia) #1447759
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.
1
#ifndef __ASSEMBLY___ 
2
typedef enum { ENUM_A, ENUM_B, ... } enumvalues;
3
#else 
4

5
#define ENUM_A 0
6
#define ENUM_B 1
7
...
8

9
#endif

TIA
Moderator #1448019
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.
Attached files:
Guest #1448349
Perhaps something like this?
1
#ifdef __ASSEMBLY__
2
#define BEGIN_ENUM
3
#define ENUM_VAL(name, value) .equ name, value
4
#define END_ENUM(enum_name)
5
#else
6
#define BEGIN_ENUM typedef enum {
7
#define ENUM_VAL(name, value) name = value,
8
#define END_ENUM(enum_name) } enum_name;
9
#endif
10

11

12
BEGIN_ENUM
13
ENUM_VAL(A, 0)
14
ENUM_VAL(B, 1)
15
END_ENUM(foo)
Guest #1448353
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.
OP (Company: Universiti Sains Malaysia) #1448711
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.
Guest #1449573
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.
Guest #1449857
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.

1
#ifdef __ASSEMBLY__
2
#define BEGIN_ENUM .set last_enum_value, 0
3
.macro enum_val name
4
.equiv \name, last_enum_value
5
.set last_enum_value, last_enum_value + 1
6
.endm
7
#define END_ENUM(name)
8
#define ENUM_VAL(name) enum_val name
9
#else
10
#define BEGIN_ENUM typedef enum {
11
#define END_ENUM(name) } name;
12
#define ENUM_VAL(name) name,
13
#endif
14

15
BEGIN_ENUM
16
ENUM_VAL(A)
17
ENUM_VAL(B)
18
ENUM_VAL(C)
19
END_ENUM(foo)
OP (Company: Universiti Sains Malaysia) #1451375
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'
1
#ifdef __ASSEMBLY__
2

3

4
  .set last_enum_value, 0
5
  .macro enum_val name
6
  .equiv \name, last_enum_value
7
  .set last_enum_value, last_enum_value + 1
8
  .endm
9

10
#define ENUM_BEGIN  .set last_enum_value, 0
11

12
#define ENUM_VAL(name) enum_val name
13
#define ENUM_VALASSIGN(name, value)            \
14
  .set last_enum_value, value                 ;\
15
  enum_val name
16
#define ENUM_END(enum_name)
17

18
#else
19

20
#define ENUM_BEGIN typedef enum {
21
#define ENUM_VAL(name) name,
22
#define ENUM_VALASSIGN(name, value) name = value,
23
#define ENUM_END(enum_name) } enum_name;
24

25
#endif
Guest #1451408
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.
Moderator #1451519
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

A question of your own? This thread is over 17 years old. Ask it in a thread of its own – more people read along there, and it gets answered more often and sooner.

Start a new thread

A fix, an addition or feedback on this thread? Then reply here.

Formatting
  • [c]C-Code[/c]
  • [code]code in other languages, ASCII drawings[/code]
  • [math]formula (LaTeX syntax)[/math]
  • [[Title]] – link to an article
  • Link to another post: right-click its post ID (#8078628), copy the address, paste it into the text

More about formatting

Post long source code as an attachment, not in the text.

Already registered? Log in

Not shown to anyone. We send you a link; your post appears once you confirm it there.

By submitting you create a free account and accept the terms of use.