Skip to contentSkip to conversation

lib32: Add support for linking 32bit programs on 64bit

RFC PATCH New Cyril Hrubis 3 participants 9 messages Mar 28, 2017 – Mar 29, 2017

lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/1 lib32: Add support for linking 32bit programs on 64bit

This is proof of concept for building 32bit testcases on 64bit platform.

What we do is:

* Configure test if compiler supports -m32
TODO: Does 32bit compiler accept -m32?
If so, we should fail the test on 32bit
platforms by default.

* The directory lib32 contains symlinks of minimal set of sources needed to link newlib testcase + Makefile.

* The testcases.mk builds 32bit library as well if 32bit compiler was installed (-m32 configure test was succesful)

* And finally the env_post.mk switches between lib and lib32 depeding on if -m32 was passed in the CFLAGS

TODO: Check if LTP works with -m32 in CFLAGS passed to configure as well

---
 configure.ac                               |  1 +
 include/mk/config.mk.in                    |  2 ++
 include/mk/env_post.mk                     |  4 ++++
 include/mk/testcases.mk                    |  9 +++++++
 lib32/Makefile                             | 38 ++++++++++++++++++++++++++++++
 lib32/errnos.h                             |  1 +
 lib32/ltp_priv.h                           |  1 +
 lib32/safe_file_ops.c                      |  1 +
 lib32/safe_macros.c                        |  1 +
 lib32/signame.h                            |  1 +
 lib32/tst_ansi_color.c                     |  1 +
 lib32/tst_checkpoint.c                     |  1 +
 lib32/tst_device.c                         |  1 +
 lib32/tst_fill_file.c                      |  1 +
 lib32/tst_kvercmp.c                        |  1 +
 lib32/tst_mkfs.c                           |  1 +
 lib32/tst_res.c                            |  1 +
 lib32/tst_resource.c                       |  1 +
 lib32/tst_run_cmd.c                        |  1 +
 lib32/tst_safe_macros.c                    |  1 +
 lib32/tst_test.c                           |  1 +
 lib32/tst_tmpdir.c                         |  1 +
 m4/ltp-m32.m4                              | 36 ++++++++++++++++++++++++++++
 testcases/kernel/syscalls/add_key/Makefile |  2 ++
 24 files changed, 109 insertions(+)
 create mode 100644 lib32/Makefile
 create mode 120000 lib32/errnos.h
 create mode 120000 lib32/ltp_priv.h
 create mode 120000 lib32/safe_file_ops.c
 create mode 120000 lib32/safe_macros.c
 create mode 120000 lib32/signame.h
 create mode 120000 lib32/tst_ansi_color.c
 create mode 120000 lib32/tst_checkpoint.c
 create mode 120000 lib32/tst_device.c
 create mode 120000 lib32/tst_fill_file.c
 create mode 120000 lib32/tst_kvercmp.c
 create mode 120000 lib32/tst_mkfs.c
 create mode 120000 lib32/tst_res.c
 create mode 120000 lib32/tst_resource.c
 create mode 120000 lib32/tst_run_cmd.c
 create mode 120000 lib32/tst_safe_macros.c
 create mode 120000 lib32/tst_test.c
 create mode 120000 lib32/tst_tmpdir.c
 create mode 100644 m4/ltp-m32.m4
configure.ac +1 -0
index 6b765f0..3c519d3 100644
@@ -190,5 +190,6 @@ LTP_CHECK_EPOLL_PWAIT
 LTP_CHECK_KEYUTILS_SUPPORT
 LTP_CHECK_SYNC_ADD_AND_FETCH
 LTP_CHECK_BUILTIN_CLEAR_CACHE
+LTP_CHECK_CC_M32
 
 AC_OUTPUT
include/mk/config.mk.in +2 -0
index dde2a9e..c160211 100644
@@ -76,6 +76,8 @@ LDFLAGS			+= $(WLDFLAGS)
 CFLAGS			+= $(DEBUG_CFLAGS) $(OPT_CFLAGS) $(WCFLAGS)
 CXXFLAGS		+= $(DEBUG_CXXFLAGS) $(OPT_CXXFLAGS) $(WCXXFLAGS)
 
+CC_M32			:= @CC_M32@
+
 LINUX_VERSION		:= @LINUX_VERSION@
 LINUX_DIR		:= @LINUX_DIR@
 LINUX_VERSION_MAJOR	:= @LINUX_VERSION_MAJOR@
include/mk/env_post.mk +4 -0
index 4c57fff..fdf13e2 100644
@@ -35,7 +35,11 @@ vpath %.c $(abs_srcdir)
 # For config.h, et all.
 CPPFLAGS			+= -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/include/old/
 
+ifeq ($(filter -m32,$(CFLAGS)),)
 LDFLAGS				+= -L$(top_builddir)/lib
+else
+LDFLAGS				+= -L$(top_builddir)/lib32
+endif
 
 ifeq ($(UCLINUX),1)
 CPPFLAGS			+= -D__UCLIBC__ -DUCLINUX
include/mk/testcases.mk +9 -0
index f453f4e..03446f2 100644
@@ -30,8 +30,10 @@ TKI_DIR		:= testcases/kernel/include
 LSN_H		:= $(abs_top_builddir)/$(TKI_DIR)/linux_syscall_numbers.h
 
 LIBLTP_DIR	:= $(abs_top_builddir)/lib
+LIBLTP_DIR32	:= $(abs_top_builddir)/lib32
 
 LIBLTP		:= $(LIBLTP_DIR)/libltp.a
+LIBLTP32	:= $(LIBLTP_DIR32)/libltp.a
 
 $(APICMDS_DIR)/tst_kvercmp: $(APICMDS_DIR)
 	$(MAKE) -C "$^" -f "$(abs_top_srcdir)/tools/apicmds/Makefile" all
@@ -39,11 +41,18 @@ $(APICMDS_DIR)/tst_kvercmp: $(APICMDS_DIR)
 $(LIBLTP): $(LIBLTP_DIR)
 	$(MAKE) -C "$^" -f "$(abs_top_srcdir)/lib/Makefile" all
 
+$(LIBLTP32): $(LIBLTP_DIR32)
+	$(MAKE) -C "$^" -f "$(abs_top_srcdir)/lib32/Makefile" all
+
 $(LSN_H): $(abs_top_builddir)/$(TKI_DIR)
 	$(MAKE) -C "$^" -f "$(abs_top_srcdir)/$(TKI_DIR)/Makefile" all
 
 MAKE_DEPS	:= $(LIBLTP) $(LSN_H)
 
+ifneq ($(CC_M32),)
+MAKE_DEPS	+= $(LIBLTP32)
+endif
+
 # For linux_syscall_numbers.h
 CPPFLAGS	+= -I$(abs_top_builddir)/$(TKI_DIR)
 
lib32/Makefile new file +38 -0
new file mode 100644
index 0000000..221b71e
@@ -0,0 +1,38 @@
+#
+#    lib Makefile.
+#
+#    Copyright (C) 2009, Cisco Systems Inc.
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License along
+#    with this program; if not, write to the Free Software Foundation, Inc.,
+#    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Ngie Cooper, July 2009
+#
+
+top_srcdir		?= ..
+
+include $(top_srcdir)/include/mk/env_pre.mk
+
+CFLAGS			+= -I -DLTPLIB -m32
+
+ifneq ($(ANDROID),1)
+FILTER_OUT_DIRS		+= android_libpthread android_librt
+else
+FILTER_OUT_LIBSRCS	+= tlibio.c tst_path_has_mnt_flags.c
+endif
+
+LIB			:= libltp.a
+
+include $(top_srcdir)/include/mk/lib.mk
+include $(top_srcdir)/include/mk/generic_trunk_target.mk
lib32/errnos.h new file +1 -0
new file mode 120000
index 0000000..caff095
@@ -0,0 +1 @@
+../lib/errnos.h
\ No newline at end of file
lib32/ltp_priv.h new file +1 -0
new file mode 120000
index 0000000..783e267
@@ -0,0 +1 @@
+../lib/ltp_priv.h
\ No newline at end of file
lib32/safe_file_ops.c new file +1 -0
new file mode 120000
index 0000000..eeb29a7
@@ -0,0 +1 @@
+../lib/safe_file_ops.c
\ No newline at end of file
lib32/safe_macros.c new file +1 -0
new file mode 120000
index 0000000..832d7ae
@@ -0,0 +1 @@
+../lib/safe_macros.c
\ No newline at end of file
lib32/signame.h new file +1 -0
new file mode 120000
index 0000000..f59345b
@@ -0,0 +1 @@
+../lib/signame.h
\ No newline at end of file
lib32/tst_ansi_color.c new file +1 -0
new file mode 120000
index 0000000..14d8c5d
@@ -0,0 +1 @@
+../lib/tst_ansi_color.c
\ No newline at end of file
lib32/tst_checkpoint.c new file +1 -0
new file mode 120000
index 0000000..28e332f
@@ -0,0 +1 @@
+../lib/tst_checkpoint.c
\ No newline at end of file
lib32/tst_device.c new file +1 -0
new file mode 120000
index 0000000..f8c7982
@@ -0,0 +1 @@
+../lib/tst_device.c
\ No newline at end of file
lib32/tst_fill_file.c new file +1 -0
new file mode 120000
index 0000000..7439f3e
@@ -0,0 +1 @@
+../lib/tst_fill_file.c
\ No newline at end of file
lib32/tst_kvercmp.c new file +1 -0
new file mode 120000
index 0000000..ac15523
@@ -0,0 +1 @@
+../lib/tst_kvercmp.c
\ No newline at end of file
lib32/tst_mkfs.c new file +1 -0
new file mode 120000
index 0000000..a0e0421
@@ -0,0 +1 @@
+../lib/tst_mkfs.c
\ No newline at end of file
lib32/tst_res.c new file +1 -0
new file mode 120000
index 0000000..f2083bc
@@ -0,0 +1 @@
+../lib/tst_res.c
\ No newline at end of file
lib32/tst_resource.c new file +1 -0
new file mode 120000
index 0000000..a3c021e
@@ -0,0 +1 @@
+../lib/tst_resource.c
\ No newline at end of file
lib32/tst_run_cmd.c new file +1 -0
new file mode 120000
index 0000000..d57dbb6
@@ -0,0 +1 @@
+../lib/tst_run_cmd.c
\ No newline at end of file
lib32/tst_safe_macros.c new file +1 -0
new file mode 120000
index 0000000..a1bf8c5
@@ -0,0 +1 @@
+../lib/tst_safe_macros.c
\ No newline at end of file
lib32/tst_test.c new file +1 -0
new file mode 120000
index 0000000..a82ad7a
@@ -0,0 +1 @@
+../lib/tst_test.c
\ No newline at end of file
lib32/tst_tmpdir.c new file +1 -0
new file mode 120000
index 0000000..a34cf42
@@ -0,0 +1 @@
+../lib/tst_tmpdir.c
\ No newline at end of file
m4/ltp-m32.m4 new file +36 -0
new file mode 100644
index 0000000..e5b3ff6
@@ -0,0 +1,36 @@
+dnl Copyright (c) 2017 Cyril Hrubis <[email protected]>
+dnl
+dnl This program is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU General Public License as
+dnl published by the Free Software Foundation; either version 2 of
+dnl the License, or (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it would be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write the Free Software Foundation,
+dnl Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+dnl
+
+AC_DEFUN([LTP_CHECK_CC_M32],[dnl
+
+flag="-m32"
+AC_MSG_CHECKING([if $CC supports $flag])
+
+backup_cflags="$CFLAGS"
+CFLAGS="$CFLAGS $flag"
+
+AC_LINK_IFELSE(
+	[AC_LANG_PROGRAM([])],
+	[CC_M32="$flag"]
+	[AC_MSG_RESULT([yes])],
+	[AC_MSG_RESULT([no])]
+)
+
+AC_SUBST(CC_M32)
+CFLAGS="$backup_cflags"
+
+])
testcases/kernel/syscalls/add_key/Makefile +2 -0
index 2ef86f0..0db5233 100644
@@ -20,4 +20,6 @@ top_srcdir		?= ../../../..
 
 include $(top_srcdir)/include/mk/testcases.mk
 
+CFLAGS += $(CC_M32)
+
 include $(top_srcdir)/include/mk/generic_leaf_target.mk
Signature · 1 line
2.10.2
#1 lore raw

RFC PATCH 1/1 lib32: Add support for linking 32bit programs on 64bit

Hi Metan!

Quoted 1 line · On Tue, 28 Mar 2017 12:01:14 +0200 "Cyril Hrubis" <[email protected]> wrote:

This is proof of concept for building 32bit testcases on 64bit platform.

Great thanks! I have tried running it and have a couple of minor issues.

Quoted 10 lines

What we do is:

* Configure test if compiler supports -m32
TODO: Does 32bit compiler accept -m32?
If so, we should fail the test on 32bit
platforms by default.

* The directory lib32 contains symlinks of minimal set of sources needed to link newlib testcase + Makefile.

Apparently missing safe_socket which is required for cve-2016-4997.c, but that is easy to fix I suppose.

Quoted 6 lines

* The testcases.mk builds 32bit library as well if 32bit compiler was installed (-m32 configure test was succesful)

* And finally the env_post.mk switches between lib and lib32 depeding on if -m32 was passed in the CFLAGS

I added "cve-2016-4997: CFLAGS += -m32" and it still tried to look in "../../lib"

include/mk/env_post.mk vpath %.c $(abs_srcdir) · line 42

Quoted 5 lines
include/mk/env_post.mk +4 -0
+ifeq ($(filter -m32,$(CFLAGS)),)
 LDFLAGS				+= -L$(top_builddir)/lib
+else
+LDFLAGS				+= -L$(top_builddir)/lib32
+endif

I was able to remove the if statement (i.e. put both dirs on the search path) and the 64-bit tests still compiled fine and so did the 32-bit test, although maybe not all linkers can be trusted to ignore libs with the wrong number of bits.

Thank you,
Richard.

#2 lore raw

RFC PATCH 1/1 lib32: Add support for linking 32bit programs on 64bit

Hi!

Quoted 5 lines
Quoted 2 lines

* The directory lib32 contains symlinks of minimal set of sources needed to link newlib testcase + Makefile.

Apparently missing safe_socket which is required for cve-2016-4997.c, but that is easy to fix I suppose.

That is just one symlink away...

Quoted 8 lines
Quoted 5 lines

* The testcases.mk builds 32bit library as well if 32bit compiler was installed (-m32 configure test was succesful)

* And finally the env_post.mk switches between lib and lib32 depeding on if -m32 was passed in the CFLAGS

I added "cve-2016-4997: CFLAGS += -m32" and it still tried to look in "../../lib"

Hmm, that is not easy to fix, since this is target specific variable and we simply do not see the -m32 in the CFLAGS in the condition below.

We would have to set the LDFLAGS per target and I'm not sure if we can easily do that.

Quoted 10 lines

include/mk/env_post.mk vpath %.c $(abs_srcdir) · line 42

Quoted 5 lines
include/mk/env_post.mk +4 -0
+ifeq ($(filter -m32,$(CFLAGS)),)
 LDFLAGS				+= -L$(top_builddir)/lib
+else
+LDFLAGS				+= -L$(top_builddir)/lib32
+endif

I was able to remove the if statement (i.e. put both dirs on the search path) and the 64-bit tests still compiled fine and so did the 32-bit test, although maybe not all linkers can be trusted to ignore libs with the wrong number of bits.

While this works mostly fine it produces warnings I would like to avoid.

Signature · 2 lines
Cyril Hrubis
[email protected]
#3 lore raw

RFC PATCH 1/1 lib32: Add support for linking 32bit programs on 64bit

Hi!

Quoted 6 lines
Quoted 2 lines

I added "cve-2016-4997: CFLAGS += -m32" and it still tried to look in "../../lib"

Hmm, that is not easy to fix, since this is target specific variable and we simply do not see the -m32 in the CFLAGS in the condition below.

Quoted 8 lines

We would have to set the LDFLAGS per target and I'm not sure if we can easily do that.

Quoted 5 lines

include/mk/env_post.mk vpath %.c $(abs_srcdir) · line 42

Quoted 5 lines
include/mk/env_post.mk +4 -0
+ifeq ($(filter -m32,$(CFLAGS)),)
 LDFLAGS				+= -L$(top_builddir)/lib
+else
+LDFLAGS				+= -L$(top_builddir)/lib32
+endif

Try with this condition instead of the above ifeqs:

$(MAKE_TARGETS): LDFLAGS += -L$(top_builddir)/lib$(subst -m,,$(filter -m32,$(CFLAGS)))

It's a bit hairy but seems to work.

Signature · 2 lines
Cyril Hrubis
[email protected]
#4 lore raw

RFC PATCH 1/1 lib32: Add support for linking 32bit programs on 64bit

Hello Metan,

Quoted 7 lines · On Tue, 28 Mar 2017 17:46:47 +0200 "Cyril Hrubis" <[email protected]> wrote:

Try with this condition instead of the above ifeqs:

$(MAKE_TARGETS): LDFLAGS += -L$(top_builddir)/lib$(subst -m,,$(filter -m32,$(CFLAGS)))

It's a bit hairy but seems to work.

It works (if added after MAKE_TARGETS is defined ofcourse) and also I symlinked in the safe socket lib, so the test now compiles and runs fine, at least on x86_64 SUSE.

I will try it on SLE-11 SP4 i586.

Thank you,
Richard.

#5 lore raw

RFC PATCH 1/1 lib32: Add support for linking 32bit programs on 64bit

In reply to Cyril Hrubis

----- Original Message -----

Quoted 14 lines

From: "Cyril Hrubis" <[email protected]>
To: [email protected]
Sent: Tuesday, 28 March, 2017 12:01:14 PM
Subject: [LTP] [RFC] [PATCH] lib32: Add support for linking 32bit programs on 64bit

This is proof of concept for building 32bit testcases on 64bit platform.

What we do is:

* Configure test if compiler supports -m32
TODO: Does 32bit compiler accept -m32?
If so, we should fail the test on 32bit
platforms by default.

Quoted 9 lines

* The directory lib32 contains symlinks of minimal set of sources needed to link newlib testcase + Makefile.

* The testcases.mk builds 32bit library as well if 32bit compiler was installed (-m32 configure test was succesful)

* And finally the env_post.mk switches between lib and lib32 depeding on if -m32 was passed in the CFLAGS

One issue I ran into is that configure checks can vary between default and -m32. Here's one exception from RHEL5.6:

# cat 1.c 
int main(void) {
        int i = 0;
        return __sync_add_and_fetch(&i, 1);
}
# gcc 1.c 
# gcc -m32 1.c 
/tmp/ccwrlcJi.o: In function `main':
1.c:(.text+0x27): undefined reference to `__sync_add_and_fetch_4'
collect2: ld returned 1 exit status
Quoted 1 line

TODO: Check if LTP works with -m32 in CFLAGS passed to configure as well

This fails for me on RHEL7:

# make
make[1]: Entering directory `/root/ltp/lib/newlib_tests'
gcc -m32 -g -O2 -fno-strict-aliasing -pipe -Wall -W -Wold-style-definition -W -Wall  -I../../include -I../../include -I../../include/old/   -L../../lib32  test14.c   -lltp -o test14
/tmp/ccPZUDSr.o: In function `cleanup':
/root/ltp/lib/newlib_tests/test14.c:31: undefined reference to `safe_fopen'
/root/ltp/lib/newlib_tests/test14.c:32: undefined reference to `safe_socket'
collect2: error: ld returned 1 exit status
make[1]: *** [test14] Error 1
make[1]: Leaving directory `/root/ltp/lib/newlib_tests'
make: *** [all] Error 2

I ran into one other problem, but I don't think that's relevant for this patch. I'll follow up in separate email thread.

Regards,
Jan

#6 lore raw

RFC PATCH 1/1 lib32: Add support for linking 32bit programs on 64bit

Hi!

Quoted 24 lines
Quoted 5 lines

* Configure test if compiler supports -m32
TODO: Does 32bit compiler accept -m32?
If so, we should fail the test on 32bit
platforms by default.

Quoted 9 lines

* The directory lib32 contains symlinks of minimal set of sources needed to link newlib testcase + Makefile.

* The testcases.mk builds 32bit library as well if 32bit compiler was installed (-m32 configure test was succesful)

* And finally the env_post.mk switches between lib and lib32 depeding on if -m32 was passed in the CFLAGS

One issue I ran into is that configure checks can vary between default and -m32. Here's one exception from RHEL5.6:

# cat 1.c 
int main(void) {
        int i = 0;
        return __sync_add_and_fetch(&i, 1);
}
Quoted 5 lines
# gcc 1.c 
# gcc -m32 1.c 
/tmp/ccwrlcJi.o: In function `main':
1.c:(.text+0x27): undefined reference to `__sync_add_and_fetch_4'
collect2: ld returned 1 exit status

Right, we would have to check for atomic operations with -m32 as well.

I guess that we can add -DUSE_M32 into the lib32/Makefile and add a few ifdefs into the tst_atomic.h something as:

#if (defined(USE_M32) && HAVE_SYNC_AND_FETCH32 == 1) || \
    (!defined(USE_M32) && HAVE_SYNC_AND_FETCH == 1)

...
#elif ...
...

Quoted 4 lines
Quoted 1 line

TODO: Check if LTP works with -m32 in CFLAGS passed to configure as well

This fails for me on RHEL7:

Quoted 10 lines
# make
make[1]: Entering directory `/root/ltp/lib/newlib_tests'
gcc -m32 -g -O2 -fno-strict-aliasing -pipe -Wall -W -Wold-style-definition -W -Wall  -I../../include -I../../include -I../../include/old/   -L../../lib32  test14.c   -lltp -o test14
/tmp/ccPZUDSr.o: In function `cleanup':
/root/ltp/lib/newlib_tests/test14.c:31: undefined reference to `safe_fopen'
/root/ltp/lib/newlib_tests/test14.c:32: undefined reference to `safe_socket'
collect2: error: ld returned 1 exit status
make[1]: *** [test14] Error 1
make[1]: Leaving directory `/root/ltp/lib/newlib_tests'
make: *** [all] Error 2

This is likely because we try to link against lib32 since -m32 is passed in CFLAGS but lib32/ directory links only subset of the C sources. I would like to disable all the lib32 machinery either when we run on 32bit machine or if -m32 was passed to the configure and use lib32 only in a case that we run on 64 bit machine and want to link 32 bit binary.

Signature · 2 lines
Cyril Hrubis
[email protected]
#7 lore raw

RFC PATCH 1/1 lib32: Add support for linking 32bit programs on 64bit

In reply to Cyril Hrubis

Hi Metan,

Quoted 9 lines · On Tue, 28 Mar 2017 12:01:14 +0200 "Cyril Hrubis" <[email protected]> wrote:

This is proof of concept for building 32bit testcases on 64bit platform.

What we do is:

* Configure test if compiler supports -m32
TODO: Does 32bit compiler accept -m32?
If so, we should fail the test on 32bit
platforms by default.

Yes it does accept -m32. I think the best thing to do is call tst_kernelbits(), as you suggested, at runtime anyway, as someone might be running a 32bit compiler on a 64bit kernel and/or cross compiling.

Also it turns out that I am using some C syntax which is not accepted by GCC 4.3.4. This is annoying considering the tests compile fine with -std=C99 on GCC 6.

Thank you,
Richard.

#8 lore raw

RFC PATCH 1/1 lib32: Add support for linking 32bit programs on 64bit

Quoted 5 lines · On Wed, 29 Mar 2017 14:48:00 +0200 "Richard Palethorpe"…

Also it turns out that I am using some C syntax which is not accepted by GCC 4.3.4. This is annoying considering the tests compile fine with -std=C99 on GCC 6.

Spoke too soon, it is just missing struct definitions.