Have GAS generate instruction from inline assembly? - gcc

I'm trying to assemble a file that uses ARM's CRC instruction. The assembler is producing an error Error: selected processor does not support 'crc32b w1,w0,w0'.
There are runtime checks in place, so we are safe with the instruction. The technique works fine on i686 and x86_64. For example, I can assemble a file that uses Intel CRC intrinsics or SHA Intrinsics without -mcrc or -msha (and on a machine without the features).
Here is the test case:
$ cat test.cxx
#include <arm_neon.h>
#define GCC_INLINE_ATTRIB __attribute__((__gnu_inline__, __always_inline__, __artificial__))
#if defined(__GNUC__) && !defined(__ARM_FEATURE_CRC32)
__inline unsigned int GCC_INLINE_ATTRIB
CRC32B(unsigned int crc, unsigned char v)
{
unsigned int r;
asm ("crc32b %w2, %w1, %w0" : "=r"(r) : "r"(crc), "r"((unsigned int)v));
return r;
}
#else
// Use the intrinsic
# define CRC32B(a,b) __crc32b(a,b)
#endif
int main(int argc, char* argv[])
{
return CRC32B(argc, argc);
}
And here is the result:
$ g++ test.cxx -c
/tmp/ccqHBPUf.s: Assembler messages:
/tmp/ccqHBPUf.s:23: Error: selected processor does not support `crc32b w1,w0,w0'
Placing the ASM code in a source file and compiling with different options is not feasible because CRC32B will be used in C++ header files, too.
How do I get GAS to assemble the instruction?
GCC's configuration and options are the reason we are trying to do things this way. User's don't read manuals, so they won't add -march=armv8-a+crc+crypto -mtune=cortex-a53 to CFLAGS and CXXFLAGS.
In addition, distros compile to a "least capable" machine, so we want the hardware acceleration routines available. When the library is provided by a distro like Linaro, both code paths (software CRC and hardware accelerated CRC) will be available.
The machine is a LeMaker HiKey, which is ARMv8/Aarch64. It has an A53 processor with CRC and Crypto (CRC and Crypto is optional under the architecture):
$ cat /proc/cpuinfo
Processor : AArch64 Processor rev 3 (aarch64)
processor : 0
...
processor : 7
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x41
CPU architecture: AArch64
GCC lacks most of the usual defines one expects to be present by default:
$ g++ -dM -E - </dev/null | sort | egrep -i '(arm|neon|aarch|asimd)'
#define __aarch64__ 1
#define __AARCH64_CMODEL_SMALL__ 1
#define __AARCH64EL__ 1
Using GCC's -march=native does not work on ARM:
$ g++ -march=native -dM -E - </dev/null | sort | egrep -i '(arm|neon|aarch|asimd)'
cc1: error: unknown value ‘native’ for -march
And Clang:
$ clang++ -dM -E - </dev/null | sort | egrep -i '(arm|neon|aarch|asimd)'
#define __AARCH64EL__ 1
#define __ARM_64BIT_STATE 1
#define __ARM_ACLE 200
#define __ARM_ALIGN_MAX_STACK_PWR 4
#define __ARM_ARCH 8
#define __ARM_ARCH_ISA_A64 1
#define __ARM_ARCH_PROFILE 'A'
#define __ARM_FEATURE_CLZ 1
#define __ARM_FEATURE_DIV 1
#define __ARM_FEATURE_FMA 1
#define __ARM_FEATURE_UNALIGNED 1
#define __ARM_FP 0xe
#define __ARM_FP16_FORMAT_IEEE 1
#define __ARM_FP_FENV_ROUNDING 1
#define __ARM_NEON 1
#define __ARM_NEON_FP 0xe
#define __ARM_PCS_AAPCS64 1
#define __ARM_SIZEOF_MINIMAL_ENUM 4
#define __ARM_SIZEOF_WCHAR_T 4
#define __aarch64__ 1
GCC version:
$ gcc -v
...
gcc version 4.9.2 (Debian/Linaro 4.9.2-10)
GAS version:
$ as -v
GNU assembler version 2.24 (aarch64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.24

This answer came from Jiong Wang on the Binutils mailing list. It bypasses GAS's architectural requirements and plays well with GCC:
__inline unsigned int GCC_INLINE_ATTRIB
CRC32W(unsigned int crc, unsigned int val)
{
#if 1
volatile unsigned int res;
asm ("\n"
"\t" ".set reg_x0, 0\n"
"\t" ".set reg_x1, 1\n"
"\t" ".set reg_x2, 2\n"
"\t" ".set reg_x3, 3\n"
"\t" ".set reg_x4, 4\n"
"\t" ".set reg_x5, 5\n"
"\t" ".set reg_x6, 6\n"
"\t" ".set reg_x7, 7\n"
"\t" "#crc32w %w0, %w1, %w2\n"
"\t" ".inst 0x1ac04800 | (reg_%2 << 16) | (reg_%1 << 5) | (reg_%0)\n"
: "=r"(res) : "r"(crc), "r"(val)
);
return res;
#else
volatile unsigned int res;
asm (".cpu generic+fp+simd+crc+crypto \n"
"crc32w %w0, %w1, %w2 \n"
: "=r"(res) : "r"(crc), "r"(val));
return res;
#endif
}
The second one commented out by the preprocessor block was suggested by Nick Clifton on the Binutils mailing list. The idea is GCC generates code using the ISA based on -march=XXX, so it does not matter if we increase capabilities to get past the assembler. We decided to go with Wang's answer because we did not want potential side effects from modifying the .cpu.
And the verification with GCC 4.8 and Binutils 2.24:
$ g++ -O1 test.cxx -c
$ objdump --disassemble test.o
test.o: file format elf64-littleaarch64
Disassembly of section .text:
0000000000000000 <main>:
0: 12001c01 and w1, w0, #0xff
4: 1ac14800 crc32w w0, w0, w1
8: d65f03c0 ret

Related

gcc define function-like macro using -D argument for printf

This is quite similar to GCC define function-like macros using -D argument but I couldn't find a relation to my use case.
Consider the following code, main.c:
#include <stdio.h>
const char greeting[] = "hello world";
//#define printf(fmt, ...) (0)
int main() {
printf("%s!\n", greeting);
return 0;
}
If I compile and run this, it works as expected:
$ gcc -Wall -g main.c -o main.exe
$ ./main.exe
hello world!
$
Ok, now I want to How to disable printf function? so I uncomment the #define in the code; I get some warnings, but things again work as as expected (as there is no printout):
$ gcc -Wall -g main.c -o main.exe
main.c: In function 'main':
main.c:5:26: warning: statement with no effect [-Wunused-value]
5 | #define printf(fmt, ...) (0)
| ^
main.c:8:5: note: in expansion of macro 'printf'
8 | printf("%s!\n", greeting);
| ^~~~~~
$ ./main.exe
$
Now, go back to the example as originally posted - that is, comment the #define like - and let's try to set that define via the command-line -D argument:
$ gcc -Wall -D'printf(fmt, ...)=(0)' -g main.c -o main.exe
<command-line>: error: expected identifier or '(' before numeric constant
main.c: In function 'main':
<command-line>: warning: statement with no effect [-Wunused-value]
main.c:8:5: note: in expansion of macro 'printf'
8 | printf("%s!\n", greeting);
| ^~~~~~
Well, the command line argument -D'printf(fmt, ...)=(0)' causes the compilation to fail.
Is there any way I can format this macro somehow, so I can set it via the gcc command line using the -D argument? (Bonus: can it be formulated somehow, so it does not raise warnings like "statement with no effect")
EDIT: contents of C:/msys64/mingw64/include/stdio.h lines 366 to 372:
366 __mingw_ovr
367 __attribute__((__format__ (gnu_printf, 1, 2))) __MINGW_ATTRIB_NONNULL(1)
368 int printf (const char *__format, ...)
369 {
370 int __retval;
371 __builtin_va_list __local_argv; __builtin_va_start( __local_argv, __format );
372 __retval = __mingw_vfprintf( stdout, __format, __local_argv );
373 __builtin_va_end( __local_argv );
374 return __retval;
375 }
When you use:
#define printf(fmt, ...) (0)
The preprocessor turns the code into this:
int main() {
(0);
return 0;
}
That free standing (0) is not allowed. However if you define it this way:
#define printf(fmt, ...)
You can also use the command line definition:
"-Dprintf(fmt, ...)="
Everything works.

When compiled inb and outb in inline assembly produce "Error: operand type mismatch"

I'm trying to code the simplest of the kernels for 64 bits arch and I'm having trouble with keyboard input.
I'm currently implementing this two functions to manage I/O
unsigned char inportb (unsigned short _port)
{
unsigned char rv;
__asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (_port));
return rv;
}
void outportb (unsigned short _port, unsigned char _data)
{
__asm__ __volatile__ ("outb %1, %0" : : "dN" (_port), "a" (_data));
}
But I'm getting this assembler error:
main.c: Mensajes del ensamblador:
main.c:51: Error: no coincide el tipo de operando para «in»
main.c:61: Error: no coincide el tipo de operando para «out»
Or in English:
main.c: Assembler messages:
main.c:51: Error: operand type mismatch for `in'
main.c:61: Error: operand type mismatch for `out'
My guess is that this code (that I got from http://www.osdever.net/bkerndev/Docs/creatingmain.htm) is designed for 32 bits assembly.
Any help on how to solve my problem would be greatly appreciated.
I build and run everything with this script
#!/bin/bash
nasm -f bin boot.asm -o boot.bin
nasm -f elf64 loader.asm -o loader.o
#cc -m64 -ffreestanding -fno-builtin -nostdlib -c main.c
cc -m64 -masm=intel -c main.c
ld -Ttext 0x100000 -o kernel.elf loader.o main.o
objcopy -R .note -R .comment -S -O binary kernel.elf kernel.bin
dd if=/dev/zero of=image.bin bs=512 count=2880
dd if=boot.bin of=image.bin conv=notrunc
dd if=kernel.bin of=image.bin conv=notrunc bs=512 seek=1
rm ./boot.bin ./kernel.bin ./main.o ./loader.o ./kernel.elf
qemu-system-x86_64 image.bin
By default GCC uses AT&T assembly syntax when generating assembly code from C code. This can be overridden by using the -masm=intel GCC compile option. In the update to your question you have -masm=intel in your GCC command line:
cc -m64 -masm=intel -c main.c
The code you found was designed for AT&T syntax where the source operand of an instruction is first and the destination is second. -masm=intel option has reversed that behavior. You have two choices. Reverse the operands in the inline assembly so they are destination, source (intel syntax) like this:
unsigned char inportb (unsigned short _port)
{
unsigned char rv;
__asm__ __volatile__ ("inb %0, %1" : "=a" (rv) : "dN" (_port));
return rv;
}
void outportb (unsigned short _port, unsigned char _data)
{
__asm__ __volatile__ ("outb %0, %1" : : "dN" (_port), "a" (_data));
}
The other option is to remove -masm=intel option from your GCC command line and keep the code as is. This might be preferable as a significant amount of OS Development code uses AT&T syntax for inline assembly.
Note: You might want to consider using gcc instead of just cc

for XCode, default C++ language dialect?

In Xcode6, what's the "compiler default" for C++ language dialect.
I am using a C++ new feature std:max(a,b,c)
if I use "Compiler Default", it failed to compile.
When I changed to "C++11 or GNUC++11", it compiles fine.
I am wondering if compiler default is C++98?
I ran below code to get - GNU C++ 98.
#include <iostream>
int main()
{
//gnu mode
#ifndef __STRICT_ANSI__
std::cout << "GNU - ";
#endif
// C++ iso standard
#if __cplusplus == 199711L
std::cout << "C++98" << std::endl;
#elif __cplusplus == 201103L
std::cout << "C++11" << std::endl;
#elif __cplusplus > 201103L
std::cout << "C++14" << std::endl;
#endif
}
Macros chosen
__cplusplus - From gcc online documentation
Depending on the language standard selected, the value of the macro is
199711L, as mandated by the 1998 C++ standard; 201103L, per the 2011
C++ standard; an unspecified value strictly larger than 201103L for
the experimental languages enabled by -std=c++1y and -std=gnu++1y.
__STRICT_ANSI__ - From clang user manual
Differences between all c* and gnu* modes => c* modes define
__STRICT_ANSI__
As a side note, __STRICT_ANSI__ for GNU standard differentiation could also be found from this SO answer
$ g++ -E -dM -std=c++11 -x c++ /dev/null >b
$ g++ -E -dM -std=gnu++11 -x c++ /dev/null >a
$ diff -u a b
--- a 2014-12-19 12:27:11.000000000 +0530
+++ b 2014-12-19 12:27:05.000000000 +0530
## -144,6 +144,7 ##
#define __STDC_UTF_16__ 1
#define __STDC_UTF_32__ 1
#define __STDC__ 1
+#define __STRICT_ANSI__ 1
#define __UINTMAX_TYPE__ long unsigned int
#define __USER_LABEL_PREFIX__ _
#define __VERSION__ "4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.54)"

How to solve bad instruction `vadd.i16 q0,q0,q0' when attempting to check gcc for neon instruction

Checking gcc supports failed for neon instruction vadd.i16 q0,q0,q0
test.c
int main ()
{
__asm__("vadd.i16 q0, q0, q0"); return 0;
}
arm-linux-androideabi-gcc test.c
/tmp/ccfc8m0G.s: Assembler messages:
/tmp/ccfc8m0G.s:24: Error: bad instruction `vadd.i16 q0,q0,q0'
Tried with flags -mcpu=cortex-a8 -mfpu=neon but stil no success
Above code was used to test gcc support for neon instruction.
Actually i am trying to build x264 with NEON support for ARM platformAfter running configure script
x264 config log file contains
Command line options: "--cross-prefix=arm-linux-androideabi-" "--enable-pic" "--extra- cflags=-mcpu=cortex-a8" "--host=arm-linux"
checking whether arm-linux-androideabi-gcc works... yes
checking whether arm-linux-androideabi-gcc supports for( int i = 0; i < 9; i++ ); with -std=gnu99... yes
checking whether arm-linux-androideabi-gcc supports __asm__("rev ip, ip");... yes
checking whether arm-linux-androideabi-gcc supports __asm__("movt r0, #0");... yes
checking whether arm-linux-androideabi-gcc supports __asm__("vadd.i16 q0, q0, q0");... no
arm-linux-androideabi-gcc conftest.c -Wall -I. -I$(SRCPATH) -mcpu=cortex-a8 -std=gnu99 -lm -o conftest
E:\cygwin\tmp\ccVtVI1i.s: Assembler messages:
E:\cygwin\tmp\ccVtVI1i.s:24: Error: bad instruction `vadd.i16 q0,q0,q0'
--------------------------------------------------
Failed program was:
--------------------------------------------------
int main () { __asm__("vadd.i16 q0, q0, q0"); return 0; }
--------------------------------------------------
config.h contains
#define HAVE_MALLOC_H 1
#define HAVE_ARMV6 1
#define HAVE_ARMV6T2 1
#define ARCH_ARM 1
#define SYS_LINUX 1
#define HAVE_VECTOREXT 1
#define fseek fseeko
#define ftell ftello
#define HAVE_GPL 1
#define HAVE_INTERLACED 1
#define HAVE_ALTIVEC 0
#define HAVE_ALTIVEC_H 0
#define HAVE_MMX 0
#define HAVE_NEON 0
#define HAVE_BEOSTHREAD 0
#define HAVE_POSIXTHREAD 0
#define HAVE_WIN32THREAD 0
#define HAVE_THREAD 0
#define HAVE_LOG2F 0
#define HAVE_VISUALIZE 0
#define HAVE_SWSCALE 0
#define HAVE_LAVF 0
#define HAVE_FFMS 0
#define HAVE_GPAC 0
#define HAVE_GF_MALLOC 0
#define HAVE_AVS 0
#define HAVE_CPU_COUNT 0
Running make command build x264 static lib based on above config.h which contains HAVE_NEON 0
**Compiler Version**
arm-linux-androideabi-gcc -v
Using built-in specs.
Target: arm-linux-androideabi
Configured with: /tmp/ndk-digit/src/build/../gcc/gcc-4.4.3/configure --prefix=/usr/local/google/digit/repo/opensource/ndk/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows --target=arm-linux-androideabi --host=i586-mingw32msvc --build=x86_64-linux-gnu --with-gnu-as --with-gnu-ld --enable-languages=c,c++ --with-gmp=/tmp/ndk-digit/build/toolchain/temp-install --with-mpfr=/tmp/ndk-digit/build/toolchain/temp-install --disable-libssp --enable-threads --disable-nls --disable-libmudflap --disable
-libgomp --disable-libstdc__-v3 --disable-sjlj-exceptions --disable-shared --disable-tls --with-float=soft --with-fpu=vfp --with-arch=armv5te --enable-target-optspace --enable-initfini-array --disable-nls --prefix=/usr/local/google/digit/repo/opensource/ndk/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows --with-sysroot=/usr/local/google/digit/repo/opensource/ndk/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/sysroot --with-binutils-version=2.20.1 --with-mpfr-version=2.4.1 --with
-gmp-version=4.2.4 --with-gcc-version=4.4.3 --with-gdb-version=6.6 --with-arch=armv5te --program-transform-name='s,^,arm-linux-androideabi-,'
Thread model: posix
gcc version 4.4.3 (GCC)
Goal is to utilize neon enabled ARM processor to boost x264 encoder performance...
I'm not really sure what it is you want to accomplish. Do you just want to see if gcc can compile neon instructions, or see if the CPU in question supports neon?
In any case:
I cannot get your code to work either. After googling around, it seems that gcc cannot really handle inline neon code very well. Apparantly the -mfpu=neon flag is somehow ignored (if you compile to .s with the -E flag, you will see that .fpu is set to softvfp even if -mfpu=neon was used)
Consider writing a .S or .s file instead. Something like this:
test.s
.cpu cortex-a8
.fpu neon
.text
.align 2
.global f
.type f, %function
f:
vadd.i16 q0, q0, q0
.size f, .-f
For what it's worth this instruction works fine for me with gcc 4.5.1 (CodeSourcery).
Try with these switches:
-mfpu=neon
-mfloat-abi=softfp
-mcpu=cortex-a8
-march=armv7-a
-mthumb

GCC #pragma to stop compilation

Is there a GCC pragma directive that will stop, halt, or abort the compilation process?
I am using GCC 4.1, but I would want the pragma to be available in GCC 3.x versions also.
You probably want #error:
$ cd /tmp
$ g++ -Wall -DGoOn -o stopthis stopthis.cpp
$ ./stopthis
Hello, world
$ g++ -Wall -o stopthis stopthis.cpp
stopthis.cpp:7:6: error: #error I had enough
File stopthis.cpp
#include <iostream>
int main(void) {
std::cout << "Hello, world\n";
#ifndef GoOn
#error I had enough
#endif
return 0;
}
I do not know about a #pragma, but #error should do what you want:
#error Failing compilation
It will terminate compilation with the error message "Failing compilation".
This works:
#include <stophere>
GCC stops when it can't find the include file. I wanted GCC to stop if C++14 was not supported.
#if __cplusplus<201300L
#error need g++14
#include <stophere>
#endif
While typically #error is sufficient (and portable), there are times when you want to use a pragma, namely, when you want to optionally cause an error within a macro.
Here is an example use which depends on C11's _Generic and _Pragma.
This example ensures var isn't an int * or a short *, but not a const int * at compile time.
Example:
#define MACRO(var) do { \
(void)_Generic(var, \
int *: 0, \
short *: 0, \
const int *: 0 _Pragma("GCC error \"const not allowed\"")); \
\
MACRO_BODY(var); \
} while (0)
#pragma GCC error "error message"
Ref: 7 Pragmas
You can use:
#pragma GCC error "my message"
But it is not standard.
An alternative is to use static_assert:
#if defined(_MSC_VER) && _MSC_VER < 1916
static_assert(false, "MSVC supported versions are 1916 and later");
#endif

Resources