Skip to contentSkip to conversation

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

RFC PATCH Superseded Cyril Hrubis 4 participants 7 messages Apr 6, 2017 – May 16, 2017

lore
Share & tools
lore
#0 lore raw

RFC PATCH v2 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

* Configure test if compiler supports atomic operations with -m32 (we have to use fallbacks in tst_atomic.h otherwise)

* 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 adding -L path to lib or lib32 depeding on if -m32 was passed in global CFLAGS and/or in the target specific CFLAGS

---

I've tried for quite minimalistic approach here, instead of trying to detect if we are on 64bit machine or not we just detect if compiler supports -m32 or not and build lib32 if we can. We will build the test library twice in case that 32bit compiler supports -m32 but that shouldn't do any harm.

---
 configure.ac                               |  1 +
 include/mk/config.mk.in                    |  2 ++
 include/mk/env_post.mk                     | 21 ++++++++++--
 include/mk/testcases.mk                    |  9 +++++
 include/tst_atomic.h                       |  3 +-
 lib32/Makefile                             | 53 ++++++++++++++++++++++++++++++
 lib32/errnos.h                             |  1 +
 lib32/safe_file_ops.c                      |  1 +
 lib32/safe_macros.c                        |  1 +
 lib32/safe_net.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                              | 50 ++++++++++++++++++++++++++++
 testcases/kernel/syscalls/add_key/Makefile |  2 ++
 25 files changed, 155 insertions(+), 3 deletions(-)
 create mode 100644 lib32/Makefile
 create mode 120000 lib32/errnos.h
 create mode 120000 lib32/safe_file_ops.c
 create mode 120000 lib32/safe_macros.c
 create mode 120000 lib32/safe_net.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 ecc9a26..1013812 100644
@@ -189,5 +189,6 @@ LTP_CHECK_EPOLL_PWAIT
 LTP_CHECK_KEYUTILS_SUPPORT
 LTP_CHECK_SYNC_ADD_AND_FETCH
 LTP_CHECK_BUILTIN_CLEAR_CACHE
+LTP_CHECK_CFLAGS_M32
 
 AC_OUTPUT
include/mk/config.mk.in +2 -0
index dde2a9e..c7d5a96 100644
@@ -76,6 +76,8 @@ LDFLAGS			+= $(WLDFLAGS)
 CFLAGS			+= $(DEBUG_CFLAGS) $(OPT_CFLAGS) $(WCFLAGS)
 CXXFLAGS		+= $(DEBUG_CXXFLAGS) $(OPT_CXXFLAGS) $(WCXXFLAGS)
 
+CFLAGS_M32		:= @CFLAGS_M32@
+
 LINUX_VERSION		:= @LINUX_VERSION@
 LINUX_DIR		:= @LINUX_DIR@
 LINUX_VERSION_MAJOR	:= @LINUX_VERSION_MAJOR@
include/mk/env_post.mk +19 -2
index 4c57fff..7d92d8a 100644
@@ -35,8 +35,6 @@ vpath %.c $(abs_srcdir)
 # For config.h, et all.
 CPPFLAGS			+= -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/include/old/
 
-LDFLAGS				+= -L$(top_builddir)/lib
-
 ifeq ($(UCLINUX),1)
 CPPFLAGS			+= -D__UCLIBC__ -DUCLINUX
 endif
@@ -56,6 +54,25 @@ MAKE_TARGETS			:= $(filter-out $(FILTER_OUT_MAKE_TARGETS),$(MAKE_TARGETS))
 
 CLEAN_TARGETS			+= $(MAKE_TARGETS) *.o *.pyc
 
+#
+# We link against lib32 only if:
+# * -m32 wasn't passed in global (configure) CFLAGS
+# * -m32 was passed in target specific CFLAGS
+#
+# The testcases must do:
+#
+# foo: CFLAGS += $(CFLAGS_M32)
+#
+# In order to compile the test in 32bit mode on 64bit arch, which takes care of
+# the situation when -m32 is not supported by compiler, since $(CFLAGS_M32) is
+# empty and we default to linking against (possibly 64bit) lib/ directory.
+#
+ifeq ($(filter -m32,$(CFLAGS)),)
+$(MAKE_TARGETS): LDFLAGS += -L$(top_builddir)/lib$(subst -m,,$(filter -m32,$(CFLAGS)))
+else
+LDFLAGS			 += -L$(top_builddir)/lib
+endif
+
 # Majority of the files end up in testcases/bin...
 INSTALL_DIR			?= testcases/bin
 
include/mk/testcases.mk +9 -0
index f453f4e..687c2ec 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 ($(CFLAGS_M32),)
+MAKE_DEPS	+= $(LIBLTP32)
+endif
+
 # For linux_syscall_numbers.h
 CPPFLAGS	+= -I$(abs_top_builddir)/$(TKI_DIR)
 
include/tst_atomic.h +2 -1
index 35a3b34..5ee8889 100644
@@ -20,7 +20,8 @@
 
 #include "config.h"
 
-#if HAVE_SYNC_ADD_AND_FETCH == 1
+#if (!defined(M32) && HAVE_SYNC_ADD_AND_FETCH == 1) \
+    || (defined(M32) && HAVE_SYNC_ADD_AND_FETCH_M32 == 1)
 static inline int tst_atomic_add_return(int i, int *v)
 {
 	return __sync_add_and_fetch(v, i);
lib32/Makefile new file +53 -0

53 lines not on this page · raw message

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/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/safe_net.c new file +1 -0
new file mode 120000
index 0000000..c367c2c
@@ -0,0 +1 @@
+../lib/safe_net.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 +50 -0

50 lines not on this page · raw message

testcases/kernel/syscalls/add_key/Makefile +2 -0
index 2ef86f0..508e502 100644
@@ -20,4 +20,6 @@ top_srcdir		?= ../../../..
 
 include $(top_srcdir)/include/mk/testcases.mk
 
+add_key02: CFLAGS += $(CFLAGS_M32)
+
 include $(top_srcdir)/include/mk/generic_leaf_target.mk
Signature · 1 line
2.10.2
#1 lore raw

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

include/mk/env_post.mk MAKE_TARGETS := $(filter-out $(FILTER_OUT_MAKE_TARGETS),$(MAKE_TARGETS)) · line 74

Quoted 5 lines · On Thu, 6 Apr 2017 14:46:41 +0200 "Cyril Hrubis" <[email protected]> wrote:
include/mk/env_post.mk +5 -0
+ifeq ($(filter -m32,$(CFLAGS)),)
+$(MAKE_TARGETS): LDFLAGS += -L$(top_builddir)/lib$(subst -m,,$(filter -m32,$(CFLAGS)))
+else
+LDFLAGS			 += -L$(top_builddir)/lib
+endif

I think this breaks the build if you do 'make CFLAGS+=-m32' or './configure CFLAGS=-m32' to build everything in compatability mode. Am I doing it wrong or is this an issue?

lib32/Makefile line 19

Quoted 5 lines
lib32/Makefile new file +5 -0
+#
+# 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.
+#

Minor nit: should be e-mail.

m4/ltp-m32.m4 line 16

Quoted 5 lines
m4/ltp-m32.m4 new file +5 -0
+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

Again, e-mail.

Tested it on 64-bit Tumbleweed and 32-bit SLES11. It works fine except for issue mentioned above. I can't comment on whether the approach is correct.

Thank you,
Richard.

#2 lore raw

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

Hi!

Quoted 9 lines

include/mk/env_post.mk MAKE_TARGETS := $(filter-out $(FILTER_OUT_MAKE_TARGETS),$(MAKE_TARGETS)) · line 74

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

I think this breaks the build if you do 'make CFLAGS+=-m32' or './configure CFLAGS=-m32' to build everything in compatability mode. Am I doing it wrong or is this an issue?

If -m32 is in CFLAGS the $(filter -m32,$(CFLAGS)) is nonempty and we will add -L$(top_builddir)/lib regardless. We will build the lib32 as well but never use it.

And you have to pass LDLAGS=-m32 to the configure script as well, since the implicit rule to build an executable from list of object files is:

$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)

Hence if you pass -m32 only to CFLAGS the compiler will fail to link the ltp-pan binary.

Passing -m32 in CFLAGS only works for testcases though, since they are compiled and linked in one try and hence use both LDFLAGS and CFLAGS.

Quoted 7 lines

lib32/Makefile line 19

Quoted 5 lines
lib32/Makefile new file +5 -0
+#
+# 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.
+#

Minor nit: should be e-mail.

Ok. I guess that we should use recent enough headers...

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

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

Hi,

Quoted 18 lines · On Fri, 7 Apr 2017 11:19:45 +0200 "Cyril Hrubis" <[email protected]> wrote:

Hi!

Quoted 9 lines

include/mk/env_post.mk MAKE_TARGETS := $(filter-out $(FILTER_OUT_MAKE_TARGETS),$(MAKE_TARGETS)) · line 74

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

I think this breaks the build if you do 'make CFLAGS+=-m32' or './configure CFLAGS=-m32' to build everything in compatability mode. Am I doing it wrong or is this an issue?

If -m32 is in CFLAGS the $(filter -m32,$(CFLAGS)) is nonempty and we will add -L$(top_builddir)/lib regardless. We will build the lib32 as well but never use it.

And you have to pass LDLAGS=-m32 to the configure script as well, since the implicit rule to build an executable from list of object files is:

Quoted 8 lines

$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)

Hence if you pass -m32 only to CFLAGS the compiler will fail to link the ltp-pan binary.

Passing -m32 in CFLAGS only works for testcases though, since they are compiled and linked in one try and hence use both LDFLAGS and CFLAGS.

OK, makes sense.

Build still fails however, because of missing 32-bit libraries, but that is just because the headers are present for the 64-bit lib and a lot of tests will try to build so long as the headers are there. I guess it would be better to also check that we can link as well, which some tests appear to do. I think it is quite a reasonable workaround to just install the libs though assuming that they will all usually be available if any 32-bit libs are.

Thank you,
Richard.

#4 lore raw

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

Hi!

Quoted 6 lines

Build still fails however, because of missing 32-bit libraries, but that is just because the headers are present for the 64-bit lib and a lot of tests will try to build so long as the headers are there. I guess it would be better to also check that we can link as well, which some tests appear to do. I think it is quite a reasonable workaround to just install the libs though assuming that they will all usually be available if any 32-bit libs are.

We may try to fix the build system to try linking with the libraries as well but that is unrelated problem that is there from the start.

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

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

In reply to Cyril Hrubis

Hi,

Quoted 12 lines · Cyril Hrubis

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

What we do is:

* Configure test if compiler supports -m32

* Configure test if compiler supports atomic operations with -m32 (we have to use fallbacks in tst_atomic.h otherwise)

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

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 adding -L path to lib or lib32 depeding on if -m32 was passed in global CFLAGS and/or in the target specific CFLAGS

I'm not sure if this has already been taken into account, but on aarch64 gcc does not recognise the -m32 switch and compilation fails if the test case has added -m32 to its CFLAGS.

Signature · 2 lines
Thank you,
Richard.
#6 lore raw

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

In reply to Cyril Hrubis
Quoted 1 line · Cyril Hrubis

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

Not sure if LTP is supposed to run on these or if lib32 accounts for them, just letting you know that they exist (and if the code doesn't support them and adding support is easy, you might want to consider it):

* IBM System z (S390) has 31bit mode, not 32bit and the corresponding gcc flag is -m31, not -m32

* Some distros (ie. RHEL5 on PPC) have 32bit userspace by default, but have a secondary 64bit userspace mode - here, both -m32 and -m64 work, just the default is not -m64

* Some distros use the x32 ABI for userspace, -mx32, still being 32bit, but not -m32

Jiri