asm keyword as identifier name in C? - c

I've seen a project which uses the asm keyword as variable name and the code compiles fine with the provided Makefile on Linux:
int
main(int ac, char *av[])
{
struct TMap *tm;
FILE *inf, *hf;
char *f, *sep;
int c, asm; // <---
asm = Defasm;
// ...
}
Here is the entire Makefile:
BIN = qbe
V = #
OBJDIR = obj
SRC = main.c util.c parse.c cfg.c mem.c ssa.c alias.c load.c copy.c \
fold.c live.c spill.c rega.c gas.c
AMD64SRC = amd64/targ.c amd64/sysv.c amd64/isel.c amd64/emit.c
ARM64SRC = arm64/targ.c arm64/abi.c arm64/isel.c arm64/emit.c
SRCALL = $(SRC) $(AMD64SRC) $(ARM64SRC)
AMD64OBJ = $(AMD64SRC:%.c=$(OBJDIR)/%.o)
ARM64OBJ = $(ARM64SRC:%.c=$(OBJDIR)/%.o)
OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(AMD64OBJ) $(ARM64OBJ)
CFLAGS += -Wall -Wextra -std=c99 -g -pedantic
$(OBJDIR)/$(BIN): $(OBJ) $(OBJDIR)/timestamp
#test -z "$(V)" || echo "ld $#"
$(V)$(CC) $(LDFLAGS) $(OBJ) -o $#
$(OBJDIR)/%.o: %.c $(OBJDIR)/timestamp
#test -z "$(V)" || echo "cc $<"
$(V)$(CC) $(CFLAGS) -c $< -o $#
$(OBJDIR)/timestamp:
#mkdir -p $(OBJDIR)
#mkdir -p $(OBJDIR)/amd64
#mkdir -p $(OBJDIR)/arm64
#touch $#
$(OBJ): all.h ops.h
$(AMD64OBJ): amd64/all.h
$(ARM64OBJ): arm64/all.h
obj/main.o: config.h
config.h:
#case `uname` in \
*Darwin*) \
echo "#define Defasm Gasmacho"; \
echo "#define Deftgt T_amd64_sysv"; \
;; \
*) \
echo "#define Defasm Gaself"; \
case `uname -m` in \
*aarch64*) \
echo "$define Deftgt T_arm64"; \
;; \
*) \
echo "#define Deftgt T_amd64_sysv";\
;; \
esac \
;; \
esac > $#
install: $(OBJDIR)/$(BIN)
mkdir -p "$(DESTDIR)/$(PREFIX)/bin/"
cp $< "$(DESTDIR)/$(PREFIX)/bin/"
uninstall:
rm -f "$(DESTDIR)/$(PREFIX)/bin/$(BIN)"
clean:
rm -fr $(OBJDIR)
clean-gen: clean
rm -f config.h
check: $(OBJDIR)/$(BIN)
tools/test.sh all
check-arm64: $(OBJDIR)/$(BIN)
TARGET=arm64 tools/test.sh all
src:
#echo $(SRCALL)
80:
#for F in $(SRCALL); \
do \
awk "{ \
gsub(/\\t/, \" \"); \
if (length(\$$0) > $#) \
printf(\"$$F:%d: %s\\n\", NR, \$$0); \
}" < $$F; \
done
.PHONY: clean clean-gen check check-arm64 src 80 install uninstall
I'm wondering how to accomplish that the compiler will allow asm as variable name (ignoring the fact that it's bad style to do this). I tried porting the Makefile to a CMakeLists.txt but the compiler threw an error because of the invalid usage of asm. How to fix this without changing the code? I already forced the C99 standard as the Makefile did and used the same C compiler flags but that didn't help:
cmake_minimum_required(VERSION 3.10.2)
project(qbe C)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_FLAGS "-Wall -Wextra -std=c99 -g -pedantic")
include_directories(amd64)
add_executable(qbe
amd64/all.h
amd64/emit.c
amd64/isel.c
amd64/sysv.c
amd64/targ.c
alias.c
all.h
cfg.c
copy.c
fold.c
gas.c
live.c
load.c
main.c
mem.c
ops.h
parse.c
rega.c
spill.c
ssa.c
util.c)
I want to use CMake due to IDE support.

asm is not a keyword of standard C, nor a reserved identifier, though the standard recognizes it as a common extension. The standard furthermore remarks that
The inclusion of any extension that may cause a strictly conforming
program to become invalid renders an implementation nonconforming.
Examples of such extensions are new keywords, extra library functions
declared in standard headers, or predefined macros with names that do
not begin with an underscore.
This is in Annex J, which is non-normative, but it merely summarizes a conclusion that can be drawn from the normative text. Thus a conforming implementation will not reject code on the basis that it uses asm as an identifier.
I find that GCC, for example, accepts usage of asm as an identifier when any of the strict conformance modes it supports is used (-std=c89 or -std=c99 or -std=c11), but rejects it with an error by default or with GNU extensions specifically enabled (e.g. with -std=gnu11). If you are using a different compiler then you will need to consult its documentation for how to obtain conformance to the standard in this area, if indeed it is possible to do so.
Addendum
As for why your CMake attempt is failing, the CMAKE_C_STANDARD property does not do what you seem to think it does. Its tells CMake to choose, if possible, compiler options that provide the features of the specified version of the C standard, but it does not request strict conformance to that standard. The docs specifically postulate it causing the -std=gnu11 option to be used under some circumstances, and that or similar inclusive options would have an effect opposite to what you want.

asm is not a standard C keyword. A conforming C compiler may not refuse compiling a program that uses asm as an identifier.
Choosing a standard explicitly with -std=c99 will also remove asm keyword. You can continue to use __asm__ however, since all names beginning with two underscores are always reserved by the implementation for any use.
However, it is still very bad style, since C99, C11 and C17 revisions do mention it as a common extension.

Related

Makefile doesn't find the rule

I have to do a makefile to compile something, but I got a problem : when I type the make command, I got an error message saying that there is no rules for one of the targets. The problem is about the path to the target, using an environment var.
Here is the given start of the Makefile :
CC = mipsel-unknown-elf-gcc
AS = mipsel-unknown-elf-as
LD = mipsel-unknown-elf-ld
DU = mipsel-unknown-elf-objdump
SYS_OBJS = reset.o \
giet.o \
common.o \
ctx_handler.o \
drivers.o \
exc_handler.o \
irq_handler.o \
sys_handler.o
APP_OBJS = stdio.o main.o
GIET ?= /(my path)/giet
SYS_PATH = $(GIET)/sys
APP_PATH = $(GIET)/app
SYS_CFLAGS = -Wall -ffreestanding -mno-gpopt -mips32 -I$(SYS_PATH) -I.
APP_CFLAGS = -Wall -ffreestanding -mno-gpopt -mips32 -I$(APP_PATH) -I.
all: sys.bin app.bin
(I am supposed to finish it)
What I tried to do (rule for sys.bin works fine) :
common.o: common.c
mipsel-unknown-elf-gcc $(SYS_CFLAGS) common.o $(SYS_PATH)/common.c
The command I'm using to compile myself is : mipsel-unknown-elf-gcc -ffreestanding -mno-gpopt -mips32 -I$GIET/sys -I. -c -o common.o $GIET/sys/common.c
Could you help me to fix this ?
Thanks :)
I don't see a -o (output file specifier) at the end of $(SYS_CFLAGS) or before the common.o in the command for your rule. That's the important difference between your makefile and your manual command.
Without that specifier, it will try to act on common.o rather than produce it, attempting to combine both common.o and $(SYS_PATH)/common.c into (most likely) a.out.
To fix it, change the rule to:
common.o: common.c
mipsel-unknown-elf-gcc $(SYS_CFLAGS) -o common.o $(SYS_PATH)/common.c
# ^^
# Add this bit here (but not these two comment lines).

how to configure.ac with optional GNU guile library ("--with-guile" )

I'm new to configure.ac, I'm trying to create a simple program that would only use the GNU guile library if the user invokes:
configure --with-guile
so the program would be something like:
#include "config.h"
#include <stdio.h>
#ifdef HAVE_GUILE
#include <libguile.h>
#endif
int main(int argc,char** argv) {
#ifdef HAVE_GUILE
printf("Guile supported\n");
scm_init_guile();
#else
printf("Guile not supported\n");
#endif
return 0;
}
GNU guile uses guile-config compile and guile-config link to obtain the path to the include directory and the libraries. I've not found a tutorial where the paths above are obtained via an external program.
So far my `configure.ac` is
AC_INIT(program, 1.0)
AC_PROG_CC
AC_CONFIG_HEADERS(config.h)
with_guile=no
AC_ARG_WITH(guile, [AS_HELP_STRING([--with-guile], [use gnu guile])],[],[with_guile=yes])
if test "x$with_guile" != no
then
AC_MSG_CHECKING(for Guile)
guile-config link > /dev/null || {
echo "configure: cannot find guile-config; is Guile installed?" 1>&2
exit 1
}
CFLAGS="$CFLAGS `guile-config compile`"
LDFLAGS="$LDFLAGS `guile-config link`"
AC_DEFINE([HAVE_GUILE],[1],[Guile supported])
#PKG_CHECK_MODULES([GUILE],[guile-2.0])
#AC_CHECK_HEADERS([libguile.h], [], [AC_MSG_ERROR([guile include files not found])])
#AC_CHECK_LIB([guile], [scm_with_guile], [AC_MSG_ERROR([guile library files not found])])
fi
dnl Process Makefile.in to create Makefile
AC_OUTPUT(Makefile)
I've removed AC_CHECK_HEADERS and AC_CHECK_LIB because they doesn't work (the files are not found).
Here I'm lost: how can I add the guile paths to CFLAGS and LDFLAGS, how can I generate HAVE_GUILE in config.h
current Makefile.in:
CC=#CC#
LD=#CC#
program: program.o
$(LD) -o $# $^
.PHONY: clean
clean:
rm -f program *.o
configure.ac:
AC_PROG_CC
AC_CONFIG_HEADERS([config.h])
AC_ARG_WITH(guile, [AS_HELP_STRING([--with-guile], [use gnu guile])],
[with_guile=yes],[with_guile=no])
AS_IF([test "x$with_guile" = xyes],
[AC_CHECK_PROG([GUILE_CONFIG],[guile-config],[guile-config])
AS_IF([test -z "$GUILE_CONFIG"],[AC_MSG_FAILURE([cannot find guile-config])])
CFLAGS="$CFLAGS `$GUILE_CONFIG compile`"
LDFLAGS="$LDFLAGS `$GUILE_CONFIG link`"
AC_DEFINE([HAVE_GUILE],[1],[Guile supported])])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
is more typical. I used a Makefile.am instead of what you did:
Makefile.am:
bin_PROGRAMS = program
program_SOURCES = src/main.c
which is more typical also.
config.h has:
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Guile supported */
#define HAVE_GUILE 1
...
Makefile has:
...
CFLAGS = -g -O2 -pthread -I/usr/include/guile/2.0
...
LDFLAGS = -lguile-2.0 -lgc

Hexagon compiler having trouble with `typedef struct mystruct *mystruct` [duplicate]

This question already has answers here:
Is it a good idea to typedef pointers?
(15 answers)
Closed 6 years ago.
I have this line in a header file:
typedef struct mystruct *mystruct;
And the corresponding struct definition in a .c file. Pretty standard practices.
I am getting this compilation error:
fatal error: typedef redefinition with different types ('struct mystruct *' vs mystruct')
This is using the Hexagon Tools Compiler (7.2.12) from Hexagon 3.0 SDK. It is officially QuIC LLVM Hexagon Clang version 7.2.12. Building for Snapdragon Flight. This should work as far as I know. It works with Ubuntu clang version 3.5.0-4ubuntu2~trusty2 (based on LLVM 3.5.0) for x86_64-pc-linux-gnu.
What is wrong here? Is this type of typedef a newer feature of C that is not implemented in the compiler, or rather are compiler differences like these common?
Edit: Actually struct is defined in a .c, not .cpp, file. Added the Makefile and make output showing compilation with Ubuntu clang, as well as the top of the header file with the troublesome typedef statment. A test is run at the end, and all 105 tests pass.
Edit2: See Jonathan Leffler's answer for cases where this works vs doesn't work.
ringbuf.h:
#include <stddef.h>
#include <sys/types.h>
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
typedef struct ringbuf_t *ringbuf_t;
Makefile:
CC=clang
CFLAGS=-O0 -g -Wall -Wpointer-arith -ftrapv -fsanitize=undefined-trap -fsanitize-undefined-trap-on-error
# or, for gcc...
#CC=gcc
#CFLAGS=-O0 -g -Wall
LD=$(CC)
LDFLAGS=-g
test: ringbuf-test
./ringbuf-test
coverage: ringbuf-test-gcov
./ringbuf-test-gcov
gcov -o ringbuf-gcov.o ringbuf.c
valgrind: ringbuf-test
valgrind ./ringbuf-test
help:
#echo "Targets:"
#echo
#echo "test - build and run ringbuf unit tests."
#echo "coverage - use gcov to check test coverage of ringbuf.c."
#echo "valgrind - use valgrind to check for memory leaks."
#echo "clean - remove all targets."
#echo "help - this message."
ringbuf-test-gcov: ringbuf-test-gcov.o ringbuf-gcov.o
gcc -o ringbuf-test-gcov --coverage $^
ringbuf-test-gcov.o: ringbuf-test.c ringbuf.h
gcc -c $< -o $#
ringbuf-gcov.o: ringbuf.c ringbuf.h
gcc --coverage -c $< -o $#
ringbuf-test: ringbuf-test.o libringbuf.so
$(LD) -o ringbuf-test $(LDFLAGS) $^ -L$(MY_LIBS_PATH) -lringbuf
ringbuf-test.o: ringbuf-test.c ringbuf.h
$(CC) $(CFLAGS) -c $< -o $#
libringbuf.so: ringbuf.o
$(CC) -shared -o libringbuf.so ringbuf.o
cp ./libringbuf.so $(MY_LIBS_PATH)/
ringbuf.o: ringbuf.c ringbuf.h
$(CC) $(CFLAGS) -fPIC -c $< -o $#
cp ./ringbuf.h $(MY_INCLUDES_PATH)/
clean:
rm -f ringbuf-test ringbuf-test-gcov *.o *.so *.gcov *.gcda *.gcno
.PHONY: clean
make output:
clang -O0 -g -Wall -Wpointer-arith -ftrapv -fsanitize=undefined-trap -fsanitize-undefined-trap-on-error -c ringbuf-test.c -o ringbuf-test.o
clang -O0 -g -Wall -Wpointer-arith -ftrapv -fsanitize=undefined-trap -fsanitize-undefined-trap-on-error -fPIC -c ringbuf.c -o ringbuf.o
cp ./ringbuf.h /home/eric/Includes/
clang -shared -o libringbuf.so ringbuf.o
cp ./libringbuf.so /home/eric/Libs/
clang -o ringbuf-test -g ringbuf-test.o libringbuf.so -L/home/eric/Libs -lringbuf
./ringbuf-test
Edit3: This actually works fine with just the Hexagon-clang compiler. It is the compilation process of the larger program that this module exists in that is being problematic. I think that it is attempting to compile this code as C++.
Your code would be fine, in C and C++, if you did not try to Use typedef for a pointer type.
The header (hdr.h for instance) could/should contain:
typedef struct mystruct mystruct;
The source (hdr.cpp for instance) could contain:
#include "hdr.h"
struct mystruct
{
const char *a;
int b;
int c;
};
#include <iostream>
int main()
{
mystruct *ap = new mystruct;
ap->a = "collywobbles";
ap->b = 1;
ap->c = 2;
std::cout << "a: " << ap->a << ", b = " << ap->b << ", c = " << ap->c << "\n";
return 0;
}
This will compile in C++, even under stringent warnings. An equivalent C main() using <stdio.h> would work in C.

Automake + libtool: pattern rule for per-object CFLAGS?

I'm using GNU Automake and libtool to compile my program. My Makefile.am looks like this:
lib_LTLIBRARIES = \
libObjectively.la
libObjectively_la_SOURCES = \
Array.c \
Class.c \
Condition.c \
Date.c \
DateFormatter.c \
Dictionary.c \
Lock.c \
Log.c \
Object.c \
String.c \
Thread.c
libObjectively_la_CFLAGS = \
-I ..
libObjectively_la_LDFLAGS = \
-pthread \
-shared
Everything compiles just fine. However, I would like to set CFLAGS for each source file using a pattern rule as well. In regular old Makefile syntax, this would look something like:
%.o: %.c
$(CC) $(CFLAGS) -D__Class=$(subst .o,,$#) -o $# $<
Is there a way to do this with Automake + libtool?
Turns out, there is no portable way to do this sort of thing.

Howto resolve a function name conflict when compiling a kernel module

I'm trying to compile a 3rd party kernel module for RHEL 5.6 and it is failing due to function name conflicts with mutex_acquire and mutex_release. This kernel module compiles cleanly on RHEL 4.7 so something changed between kernels 2.6.9 and 2.6.18. Sadly, this kernel module is no longer supported by the vendor but I do have the source code for mutex.c and mutex.h which define these functions. Unfortunately there is an object file nivxi.o upon which no source code is distributed and this object file is calling mutex_acquire and mutex_release so I cannot just simply alter their names.
As an aside, I originally attempted to just modify the names slightly and the compile errors went away but when it went to make the .ko kernel module it complained that it couldn't find mutex_acquire or mutex_release; presumably due to nivxi.o
How do I force the compiler/linker to use the function definitions in my local .c/.h files even though they trounce over like-named functions elsewhere?
mutex.h
NIVXICC void mutex_acquire(mutex_t *mutex);
NIVXICC void mutex_release(mutex_t *mutex);
nivxicc.h (just incase this is pertinent)
#ifndef NIVXICC_H
#define NIVXICC_H
#define NIVXICC __attribute__((regparm(0))) __attribute__((cdecl))
#endif
/usr/include/lockdep.h (conflicting definition)
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# ifdef CONFIG_PROVE_LOCKING
# define mutex_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i)
# else
# define mutex_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i)
# endif
# define mutex_release(l, n, i) lock_release(l, n, i)
#else
# define mutex_acquire(l, s, t, i) do { } while (0)
# define mutex_release(l, n, i) do { } while (0)
#endif
Error
# make
make -C /lib/modules/2.6.18-238.el5/build SUBDIRS=/usr/local/nivxi/src KBUILD_VERBOSE=1 modules
make[1]: Entering directory `/usr/src/kernels/2.6.18-238.el5-i686'
test -e include/linux/autoconf.h -a -e include/config/auto.conf || ( \
echo; \
echo " ERROR: Kernel configuration is invalid."; \
echo " include/linux/autoconf.h or include/config/auto.conf are missing."; \
echo " Run 'make oldconfig && make prepare' on kernel src to fix it."; \
echo; \
/bin/false)
mkdir -p /usr/local/nivxi/src/.tmp_versions
rm -f /usr/local/nivxi/src/.tmp_versions/*
make -f scripts/Makefile.build obj=/usr/local/nivxi/src
gcc -m32 -Wp,-MD,/usr/local/nivxi/src/.vxi.o.d -nostdinc -isystem \
/usr/lib/gcc/i386-redhat-linux/4.1.2/include -D__KERNEL__ -Iinclude \
-include include/linux/autoconf.h -Wall -Wundef -Wstrict-prototypes \
-Wno-trigraphs -fno-strict-aliasing -fno-common -Wstrict-prototypes \
-Wundef -Werror-implicit-function-declaration \
-fno-delete-null-pointer-checks -fwrapv -Os -pipe -msoft-float \
-fno-builtin-sprintf -fno-builtin-log2 -fno-builtin-puts \
-mpreferred-stack-boundary=2 -march=i686 -mtune=generic -mtune=generic \
-mregparm=3 -ffreestanding -Iinclude/asm-i386/mach-generic \
-Iinclude/asm-i386/mach-default -fomit-frame-pointer -g -fno-stack-protector \
-Wdeclaration-after-statement -Wno-pointer-sign -DVXI_MAJOR=0 \
-DREMAP_PAGE_RANGE_VMA -D__DEBUG__ -DMODULE -D"KBUILD_STR(s)=#s" \
-D"KBUILD_BASENAME=KBUILD_STR(vxi)" -D"KBUILD_MODNAME=KBUILD_STR(vximod)" \
-c -o /usr/local/nivxi/src/.tmp_vxi.o /usr/local/nivxi/src/vxi.c
In file included from /usr/local/nivxi/src/vxi.c:13:
/usr/local/nivxi/src/mutex.h:59:42: error: macro "mutex_acquire" requires 4 arguments, but only 1 given
In file included from /usr/local/nivxi/src/vxi.c:13:
/usr/local/nivxi/src/mutex.h:59: warning: ‘regparm’ attribute only applies to function types
/usr/local/nivxi/src/mutex.h:59: warning: ‘cdecl’ attribute only applies to function types
/usr/local/nivxi/src/mutex.h:61:42: error: macro "mutex_release" requires 3 arguments, but only 1 given
/usr/local/nivxi/src/mutex.h:61: warning: ‘regparm’ attribute only applies to function types
/usr/local/nivxi/src/mutex.h:61: warning: ‘cdecl’ attribute only applies to function types
/usr/local/nivxi/src/vxi.c:128:31: error: macro "mutex_acquire" requires 4 arguments, but only 1 given
/usr/local/nivxi/src/vxi.c:133:31: error: macro "mutex_release" requires 3 arguments, but only 1 given
/usr/local/nivxi/src/vxi.c:146:31: error: macro "mutex_acquire" requires 4 arguments, but only 1 given
/usr/local/nivxi/src/vxi.c:158:31: error: macro "mutex_release" requires 3 arguments, but only 1 given
/usr/local/nivxi/src/vxi.c: In function ‘vxi_mmap’:
/usr/local/nivxi/src/vxi.c:243: error: implicit declaration of function ‘remap_page_range’
make[2]: *** [/usr/local/nivxi/src/vxi.o] Error 1
make[1]: *** [_module_/usr/local/nivxi/src] Error 2
make[1]: Leaving directory `/usr/src/kernels/2.6.18-238.el5-i686'
make: *** [default] Error 2
The problem will not be in your object file as macros have file-scope and are replaced by the preprocessor. Thus after being compiled, the macro no longer exists as far as your nivxi.o file is concerned.
The issue is probably in your mutex.h file. I would look at the top and you will likely see an #include <lockdep.h> line. Thus once the preprocessor gets down to your function definition, it treats mutex_acquire as a token to be replaced (with the wrong number of arguments).
The easiest way to solve your problem will be to #undef mutex_acquire and #undef mutex_release at the beginning of mutex.h. This will prevent the preprocessor from replacing the tokens in your mutex.h. Since defines have file-scope, you don't need to worry about this propagating beyond your application

Resources