4

I have a weird one. I'm working on an embedded system, using the vendors header files. I'm compiling the files using GCC 4.6.3. I want to use C++ for my code, I have error I can't figure out. I'm running a vendor example program, and all I've done is changed the name of the main.c file to main.cpp. As a result, I assume, the header files are being interpreted by the C++ compiler. One of them contains the following lines:

__attribute__((naked)) static return_type signature \
  { \
     __asm( \
         "svc %0\n" \
         "bx r14" : : "I" (number) : "r0" \
     ); \
}

The files compile properly if the name of the file is main.c, I assume this is because the file is being processed by the C compiler. The error I get if I use C++ is

error: impossible constraint in 'asm'

But again, I have no problem with the C compiler. I need to call functions that use this define in C++ files. I've considered writing wrapper functions that stay on the c side and linking to them, but it would be a real pain, and less efficient. Any suggestions?

artless noise
  • 21,212
  • 6
  • 68
  • 105
Kendrick Taylor
  • 2,218
  • 2
  • 18
  • 21
  • 2
    If it's in a header file did you remember to `extern "C"` it? – Jesus Ramos Mar 29 '13 at 23:16
  • 1
    I tried it as a last ditch, however I didn't expect it to work. extern "C" only effects linkage, not compilation, as far as I know. I think what I've got is a compilation error, not a linkage error. Thanks for the suggestion though. http://stackoverflow.com/questions/1041866/in-c-source-what-is-the-effect-of-extern-c – Kendrick Taylor Mar 29 '13 at 23:19
  • I see, I skipped over the part of it being a macro :P – Jesus Ramos Mar 30 '13 at 00:03
  • It might affect the ABI too. – PlasmaHH Mar 30 '13 at 00:11
  • 1
    Are you sure the C++ compilation finds the cross compiler, and you aren't using the host compiler by accident? – fizzer Mar 30 '13 at 01:15
  • @fizzer Yeah, it's finding the C++ compiler. I can see the commands make spits out. – Kendrick Taylor Mar 30 '13 at 21:55
  • Sorry if I'm laboring the obvious. You're sure you're not passing your ARM assembler to the local x86 compiler by finding g++ on the PATH? – fizzer Mar 30 '13 at 22:14
  • @fizzer Yes, I'm 100% percent sure. The path is included. I appreciate the diligence. Sometimes it is the power cord, but this time it's not. – Kendrick Taylor Mar 31 '13 at 06:34
  • I also have this issue (in the Nordic nRF51 SDK). – Timmmm May 21 '14 at 11:33
  • A [related question](http://stackoverflow.com/questions/35213522/rewriting-gcc-inline-assembly-to-not-require-volatile-or-a-memory-clobber), which might give better code. It should be possible to just inline the `svc` instructions. – artless noise Feb 06 '16 at 22:28

2 Answers2

1

svc also known as swi is the ARM/Thumb software interrupt instruction. It only takes constants, but they are different from other register constants. Ie, mov r0, #4096. You need to use the preprocessor and token pasting if you wish to specify an immediate. number can not be a variable or register.

#define syscall(number) __attribute__((naked)) static return_type signature \
  { \
     __asm( \
         "svc " #number "\n" \
         "bx r14" : : : "r0" \
     ); \
  }

will work. Note: The # is the 'C' preprocessors stringify. Also note that it is in-efficient to look at the SVC number as it is in the I-CACHE and inspecting requires D-CACHE. Generally it is always constant and the function number is passed in a register for faster syscall's.

The gcc manual says,

'I'- Integer that is valid as an immediate operand in a data processing instruction. That is, an integer in the range 0 to 255 rotated by a multiple of 2

This is typical of Data-processing operands - immediate, section A5.1.3 of the ARM ARM. The SVC operands are either fixed 8-bits in thumb mode or fixed 24-bits in ARM mode. It maybe possible with some other constraint that I am unaware of, but at least the preprocessor's stringification will work as long as a numeric constant is passed to the macro.

I guess it is lucky that this worked from gcc and unlucky that g++ did not. You can get further insight by using -S and looking at (and posting) the output using both tools.

Edit: Your code does seem to work with gcc-4.7.2, but number is a const int local in my case, the use of number maybe the issue. Perhaps it has a subtle semantic change from 'C' to 'C++'.

artless noise
  • 21,212
  • 6
  • 68
  • 105
  • 3
    Thanks for the help. You put me on the right track with your edit. It was the datatype of number. The constants the vendor was using were defined as enums, which changes the type between C and C++. I've changed them to #define's and it's working a treat. Thanks. – Kendrick Taylor Apr 08 '13 at 19:49
  • Rather than change a whole bunch of enums to #defines, I found I could simply add a local variable with a cast to an integral type. – Christopher Mason May 22 '13 at 13:09
  • Thanks KendrickTaylor, that did the job for me! I guess we are both using nRF51? :) @ChristopherMason, could you paste a code snippet? – Timmmm May 21 '14 at 12:44
  • 1
    This cast works for me: `"bx r14" : : "I" ((uint16_t)number) : "r0"` I do this in a local file and use include order to preferentially include it, this way avoiding having to modify the Nordic SDK. – Christopher Mason Aug 09 '14 at 01:38
  • Ok, it is quite possible that the behavior will change depending on the gcc version and optimization level. Ie, it might work with the cast now, but you may have trouble if you upgrade and/or change optimization levels. The main point is the compiler must be able to deduce the value is a constant. For instance, compiling with `-O0` may not work as the compiler may leave things in a register. With higher optimization levels, it is more likely the cast will work. – artless noise Aug 11 '14 at 15:20
0

Check the GCC manual (inline assembler) for the exact meaning of the constraints for your machine. Older GCC versions have been notoriously sloppy in the checking of constraints, perhaps you are being bitten by this. It is strange that gcc and g++ (same version?) handle the code differently, it just might be a compiler bug, but I'd consider that only after all other explanations have been exhausted.

vonbrand
  • 11,412
  • 8
  • 32
  • 52