SPRUI03E June 2015 – January 2023
Share C Headers Between C and Assembly Code
Single Line:
.cdecls [options ,] " filename "[, " filename2 "[,...]]
Multiple Lines:
.cdecls [options]
%{
/*---------------------------------------------------------------------------------*/
/* C/C++ code - Typically a list of #includes and a few defines */
/*---------------------------------------------------------------------------------*/
%}
The .cdecls directive allows programmers in mixed assembly and C/C++ environments to share C headers containing declarations and prototypes between the C and assembly code. Any legal C/C++ can be used in a .cdecls block and the C/C++ declarations cause suitable assembly to be generated automatically, allowing you to reference the C/C++ constructs in assembly code; such as calling functions, allocating space, and accessing structure members; using the equivalent assembly mechanisms. While function and variable definitions are ignored, most common C/C++ elements are converted to assembly, for instance: enumerations, (non-function-like) macros, function and variable prototypes, structures, and unions.
The .cdecls options control whether the code is treated as C or C++ code; and how the .cdecls block and converted code are presented. Options must be separated by commas; they can appear in any order:
C | Treat the code in the .cdecls block as C source code (default). | |
CPP | Treat the code in the .cdecls block as C++ source code. This is the opposite of the C option. | |
NOLIST | Do not include the converted assembly code in any listing file generated for the containing assembly file (default). | |
LIST | Include the converted assembly code in any listing file generated for the containing assembly file. This is the opposite of the NOLIST option. | |
NOWARN | Do not emit warnings on STDERR about C/C++ constructs that cannot be converted while parsing the .cdecls source block (default). | |
WARN | Generate warnings on STDERR about C/C++ constructs that cannot be converted while parsing the .cdecls source block. This is the opposite of the NOWARN option. |
In the single-line format, the options are followed by one or more filenames to include. The filenames and options are separated by commas. Each file listed acts as if #include "filename" was specified in the multiple-line format.
In the multiple-line format, the line following .cdecls must contain the opening .cdecls block indicator %{. Everything after the %{, up to the closing block indicator %}, is treated as C/C++ source and processed. Ordinary assembler processing then resumes on the line following the closing %}.
The text within %{ and %} is passed to the C/C++ compiler to be converted into assembly language. Much of C language syntax, including function and variable definitions as well as function-like macros, is not supported and is ignored during the conversion. However, all of what traditionally appears in C header files is supported, including function and variable prototypes; structure and union declarations; non-function-like macros; enumerations; and #defines.
The resulting assembly language is included in the assembly file at the point of the .cdecls directive. If the LIST option is used, the converted assembly statements are printed in the listing file.
The assembly resulting from the .cdecls directive is treated similarly to a .include file. Therefore the .cdecls directive can be nested within a file being copied or included. The assembler limits nesting to ten levels; the host operating system may set additional restrictions. The assembler precedes the line numbers of copied files with a letter code to identify the level of copying. An A indicates the first copied file, B indicates a second copied file, etc.
The .cdecls directive can appear anywhere in an assembly source file, and can occur multiple times within a file. However, the C/C++ environment created by one .cdecls is not inherited by a later .cdecls; the C/C++ environment starts new for each .cdecls.
See Chapter 12 for more information on setting up and using the .cdecls directive with C header files.
In this example, the .cdecls directive is used call the C header.h file.
C header file:
#define WANT_ID 10
#define NAME "John\n"
extern int a_variable;
extern float cvt_integer(int src);
struct myCstruct { int member_a; float member_b; };
enum status_enum { OK = 1, FAILED = 256, RUNNING = 0 };
Source file:
.cdecls C,LIST,"myheader.h"
size: .int $sizeof(myCstruct)
aoffset: .int myCstruct.member_a
boffset: .int myCstruct.member_b
okvalue: .int status_enum.OK
failval: .int status_enum.FAILED
.if $defined(WANT_ID)
id .cstring NAME
.endif
Listing File:
1 .cdecls C,LIST,"myheader.h"
A 1 ; ------------------------------------------
A 2 ; Assembly Generated from C/C++ Source Code
A 3 ; ------------------------------------------
A 4
A 5 ; =========== MACRO DEFINITIONS ===========
A 6 .define "10",WANT_ID
A 7 .define """John\n""",NAME
A 8
A 9 ; =========== TYPE DEFINITIONS ===========
A 10 status_enum .enum
A 11 00000001 OK .emember 1
A 12 00000100 FAILED .emember 256
A 13 00000000 RUNNING .emember 0
A 14 .endenum
A 15
A 16 myCstruct .struct 0,4
17 ; struct size=(8 bytes|64 bits), alignment=4
A 18 00000000 member_a .field 32
19 ; int member_a - offset 0 bytes, size (4 bytes|32 bits)
A 20 00000004 member_b .field 32
21 ; float member_b - offset 4 bytes, size (4 bytes|32 bits)
A 22 00000008 .endstruct
23 ; final size=(8 bytes|64 bits)
A 24
A 25 ; =========== EXTERNAL FUNCTIONS ===========
A 26 .global _cvt_integer
A 27
A 28 ; =========== EXTERNAL VARIABLES ===========
A 29 .global _a_variable
2 00000000 00000008 size: .int $sizeof(myCstruct)
3 00000004 00000000 aoffset: .int myCstruct.member_a
4 00000008 00000004 boffset: .int myCstruct.member_b
5 0000000c 00000001 okvalue: .int status_enum.OK
6 00000010 00000100 failval: .int status_enum.FAILED
7 .if $defined(WANT_ID)
8 00000014 0000004A id .cstring NAME
00000015 0000006F
00000016 00000068
00000017 0000006E
00000018 0000000A
00000019 00000000
9 .endif