0

I am trying to compile a mixed C-code and an assembly-code project, while trying to share information between .S file and some header file, I ran into a problem.

I have created two files, as follows:

asm.S:

#include "common.h"

.space SOME_STRUCT_SIZE
.word SOME_MAGIC

.globl main
b start

start:
   ; ... code here

common.h:

struct someStruct {
    int data;
};

#define SOME_STRUCT_SIZE sizeof(struct someStruct)
#define SOME_MAGIC 0x12345678

When trying to compile the .S file (arm-linux-gnueabi-gcc -o asm asm.S), I get error messages indicating the assembler is trying to assemble the .h file, and obviously fails on the struct definition.

common.h: Assembler messages:
common.h:2: Error: bad instruction 'int data'

Is it possible to force the pre-processor to statically create both defines and insert them in a way that the assembly code can use?

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Tals
  • 468
  • 4
  • 17
  • the problem is that `sizeof` needs to be compiled by the c compiler. The preprocessor is simply a text replacing machine – pm100 Nov 16 '17 at 16:29
  • I understand, I am looking for different ways to implement this – Tals Nov 16 '17 at 16:29
  • 1
    I think this might be useful for the defines: https://stackoverflow.com/questions/4928238/include-header-with-c-declarations-in-an-assembly-file-without-errors – Thomas Blanquet Nov 16 '17 at 16:31
  • 1
    Your `.space` and `.word` directives can be just as easily implemented on the C side. You will have more issues addressing fields of your struct anyway. – Jester Nov 16 '17 at 16:31
  • You are wanting the assembler to include C code and to assemble that but that's the job of the C compiler as @pm100 states. That's not what gcc does so it can't be done. – Rob Nov 16 '17 at 16:32
  • 1
    Seems to me you need to write a c program that emits a header file that is in the form that yr assembler can accept. Should take 10 mins to implement – pm100 Nov 16 '17 at 16:33

2 Answers2

2

I implemented what @pm100 suggested, and it worked out just fine.

common_bare_gen.c:

#include "common.h"
#include <stdio.h>

void main(void){
    FILE *common_bare_fp;   
    common_bare_fp = fopen("common_bare.h", "w");

    fprintf(common_bare_fp, "#define SOME_STRUCT_SIZE 0x%08x\n", SOME_STRUCT_SIZE);
    fprintf(common_bare_fp, "#define SOME_MAGIC 0x%08x\n", SOME_MAGIC);
    fclose(common_bare_fp);
}

In asm.S I changed:

#include "common_bare.h"

And added two commands to compile and execute common_bare_gen in my Makefile.

Thanks a lot for your help!

Tals
  • 468
  • 4
  • 17
2

This may seem convoluted but it may also achieve the same goal. You could create a C macro that simply creates #defines for strings and values that may need to propagate to an assembler header. You can create a function that uses these macros to generate the defines. You can then use -S feature of GCC to output the assembly and then use GREP to sift out the defines that were generated dumping them to an include file that can be used by your assembly (.S) file.

File gnuasm.h:

#define GNUASM_DEFINE_STR(SYMBOL, STR) \
    __asm__  ("#define " SYMBOL " " #STR);

#define GNUASM_DEFINE_VAL(SYMBOL, VALUE) \
    __asm__  ("#define " SYMBOL " %a0" :: "n"(VALUE));

The trick in the macro is to use the asm directive to emit the defines. This will cause them to appear in the generated .s file. GNUASM_DEFINE_STR can be used at global scope but for GNUASM_DEFINE_VAL to work you'll need to put it in a dummy function.

Your common.h would remain unchanged:

struct someStruct {
    int data;
};

#define SOME_STRUCT_SIZE sizeof(struct someStruct)
#define SOME_MAGIC 0x12345678

Create a dummy C file (it doesn't need to be linked with your project) that includes common.h and the gnuasm.h macros file with a dummy function. In this case I'll call it common-defs.c:

#include "gnuasm.h"
#include "common.h"

/* Dummy function used to generate the defines we need */
void common_defines(void)
{
    GNUASM_DEFINE_STR("SOME_STRING", "some string");
    GNUASM_DEFINE_VAL("SOME_STRUCT_SIZE", SOME_STRUCT_SIZE);
    GNUASM_DEFINE_VAL("SOME_MAGIC", SOME_MAGIC);

    return;
}

This file is meant to be compiled and for the assembly output to be generated like this:

gcc common-defs.c -c -S

This produces a file common-defs.s. This is the assembly code that represents the C code. All the defines we emitted can then be parsed out with GREP and then output into an include file that our assembly file can include:

grep "#define" common-defs.s >common.inc

Now in our asm.S file you can include this at the top:

#include "common.inc"

The generated common.inc file would appear something like:

    #define SOME_STRING "some string"
    #define SOME_STRUCT_SIZE 4
    #define SOME_MAGIC 305419896

When using struct another useful thing for assembly are the offsets of member variables. Those could be generated like this:

GNUASM_DEFINE_VAL("SOME_STRUCT_DATA_OFFSET", offsetof(struct someStruct, data));
Michael Petch
  • 46,082
  • 8
  • 107
  • 198