aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2021-07-12 16:32:56 -0700
committerAndrew G. Morgan <morgan@kernel.org>2021-07-12 21:23:32 -0700
commitee3b25c0a877fa74d1aec88f325ac45b09963c82 (patch)
tree67bf3458179a9e80a8055232f6891c989588531f
parentf73a3691afe24fec86841eca43f5edcfbde875f3 (diff)
downloadlibcap-ee3b25c0a877fa74d1aec88f325ac45b09963c82.tar.gz
Support simply executing the built shared libraries.
Some system libraries support being run as regular executables. Now that I have figured out how to do it, add support for libcap.so and libpsx.so to print some information and exit. Note, I've explained how most of this stuff works in this answer: https://stackoverflow.com/a/68339111/14760867 Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
-rw-r--r--Make.Rules1
-rw-r--r--libcap/.gitignore4
-rw-r--r--libcap/Makefile65
-rw-r--r--libcap/empty.c1
-rw-r--r--libcap/execable.c15
-rw-r--r--libcap/execable.h84
6 files changed, 154 insertions, 16 deletions
diff --git a/Make.Rules b/Make.Rules
index 45d8912..80a8059 100644
--- a/Make.Rules
+++ b/Make.Rules
@@ -63,6 +63,7 @@ BUILD_COPTS ?= -O2
BUILD_CFLAGS ?= $(BUILD_COPTS) $(DEFINES) $(IPATH)
AR := $(CROSS_COMPILE)ar
RANLIB := $(CROSS_COMPILE)ranlib
+OBJCOPY := $(CROSS_COMPILE)objcopy
DEBUG = -g #-DDEBUG
WARNINGS=-Wall -Wwrite-strings \
-Wpointer-arith -Wcast-qual -Wcast-align \
diff --git a/libcap/.gitignore b/libcap/.gitignore
index 8f77a0e..a0771d4 100644
--- a/libcap/.gitignore
+++ b/libcap/.gitignore
@@ -9,3 +9,7 @@ _makenames
cap_test
libcap.pc
libpsx.pc
+empty
+loader.txt
+cap_magic.o
+psx_magic.o
diff --git a/libcap/Makefile b/libcap/Makefile
index bdd32a9..47cf8f4 100644
--- a/libcap/Makefile
+++ b/libcap/Makefile
@@ -9,11 +9,18 @@ include ../Make.Rules
CAPLIBNAME=$(LIBTITLE).so
STACAPLIBNAME=$(LIBTITLE).a
#
-PSXLIBNAME=libpsx.so
-STAPSXLIBNAME=libpsx.a
+PSXTITLE=libpsx
+PSXLIBNAME=$(PSXTITLE).so
+STAPSXLIBNAME=$(PSXTITLE).a
CAPFILES=cap_alloc cap_proc cap_extint cap_flag cap_text cap_file
+CAPMAGICOBJ=cap_magic.o
PSXFILES=../psx/psx
+PSXMAGICOBJ=psx_magic.o
+
+# The linker magic needed to build a dynamic library as independently
+# executable
+MAGIC=--entry=__so_start
INCLS=libcap.h cap_names.h $(INCS)
GPERF_OUTPUT = _caps_output.gperf
@@ -37,9 +44,9 @@ ifeq ($(SHARED),yes)
endif
endif
-pcs: libcap.pc
+pcs: $(LIBTITLE).pc
ifeq ($(PTHREADS),yes)
- $(MAKE) libpsx.pc
+ $(MAKE) $(PSXTITLE).pc
endif
ifeq ($(BUILD_GPERF),yes)
@@ -47,7 +54,7 @@ USE_GPERF_OUTPUT = $(GPERF_OUTPUT)
INCLUDE_GPERF_OUTPUT = -DINCLUDE_GPERF_OUTPUT='"$(GPERF_OUTPUT)"'
endif
-libcap.pc: libcap.pc.in
+$(LIBTITLE).pc: $(LIBTITLE).pc.in
sed -e 's,@prefix@,$(prefix),' \
-e 's,@exec_prefix@,$(exec_prefix),' \
-e 's,@libdir@,$(LIBDIR),' \
@@ -56,7 +63,7 @@ libcap.pc: libcap.pc.in
-e 's,@deps@,$(DEPS),' \
$< >$@
-libpsx.pc: libpsx.pc.in
+$(PSXTITLE).pc: $(PSXTITLE).pc.in
sed -e 's,@prefix@,$(prefix),' \
-e 's,@exec_prefix@,$(exec_prefix),' \
-e 's,@libdir@,$(LIBDIR),' \
@@ -93,13 +100,26 @@ $(STAPSXLIBNAME): $(PSXOBJS) include/sys/psx_syscall.h
$(RANLIB) $@
ifeq ($(SHARED),yes)
-$(CAPLIBNAME) $(MAJCAPLIBNAME) $(MINCAPLIBNAME): $(CAPOBJS)
- $(LD) $(CFLAGS) $(LDFLAGS) -Wl,-soname,$(MAJCAPLIBNAME) -o $(MINCAPLIBNAME) $^
+
+empty: empty.c
+ $(CC) -o $@ $<
+
+loader.txt: empty
+ $(OBJCOPY) --dump-section .interp=/dev/stdout $< > $@
+
+cap_magic.o: execable.h execable.c loader.txt
+ $(CC) $(CFLAGS) $(IPATH) -DLIBRARY_VERSION=\"$(LIBTITLE)-$(VERSION).$(MINOR)\" -DSHARED_LOADER=\"$(shell cat loader.txt)\" -c execable.c -o $@
+
+$(CAPLIBNAME) $(MAJCAPLIBNAME) $(MINCAPLIBNAME): $(CAPOBJS) $(CAPMAGICOBJ)
+ $(LD) $(CFLAGS) $(LDFLAGS) -Wl,-soname,$(MAJCAPLIBNAME) -o $(MINCAPLIBNAME) $^ $(MAGIC)
ln -sf $(MINCAPLIBNAME) $(MAJCAPLIBNAME)
ln -sf $(MAJCAPLIBNAME) $(CAPLIBNAME)
-$(PSXLIBNAME) $(MAJPSXLIBNAME) $(MINPSXLIBNAME): $(PSXOBJS) include/sys/psx_syscall.h
- $(LD) $(CFLAGS) $(LDFLAGS) -Wl,-soname,$(MAJPSXLIBNAME) -o $(MINPSXLIBNAME) $(PSXOBJS) $(PSXLINKFLAGS)
+psx_magic.o: execable.h execable.c loader.txt
+ $(CC) $(CFLAGS) $(IPATH) -DLIBRARY_VERSION=\"$(PSXTITLE)-$(VERSION).$(MINOR)\" -DSHARED_LOADER=\"$(shell cat loader.txt)\" -c execable.c -o $@
+
+$(PSXLIBNAME) $(MAJPSXLIBNAME) $(MINPSXLIBNAME): $(PSXOBJS) include/sys/psx_syscall.h $(PSXMAGICOBJ)
+ $(LD) $(CFLAGS) $(LDFLAGS) -Wl,-soname,$(MAJPSXLIBNAME) -o $(MINPSXLIBNAME) $(PSXOBJS) $(PSXMAGICOBJ) $(MAGIC) $(PSXLINKFLAGS)
ln -sf $(MINPSXLIBNAME) $(MAJPSXLIBNAME)
ln -sf $(MAJPSXLIBNAME) $(PSXLIBNAME)
endif
@@ -113,8 +133,20 @@ cap_text.o: cap_text.c $(USE_GPERF_OUTPUT) $(INCLS)
cap_test: cap_test.c libcap.h $(CAPOBJS)
$(CC) $(CFLAGS) $(IPATH) $< $(CAPOBJS) -o $@
+libcapsotest: $(CAPLIBNAME)
+ ./$(CAPLIBNAME)
+
+libpsxsotest: $(PSXLIBNAME)
+ ./$(PSXLIBNAME)
+
test: cap_test
./cap_test
+ifeq ($(SHARED),yes)
+ $(MAKE) libcapsotest
+ifeq ($(PTHREADS),yes)
+ $(MAKE) libpsxsotest
+endif
+endif
install: install-static
ifeq ($(SHARED),yes)
@@ -163,17 +195,17 @@ ifeq ($(FAKEROOT),)
-/sbin/ldconfig
endif
-install-common-cap: install-common libcap.pc
+install-common-cap: install-common $(LIBTITLE).pc
install -m 0644 include/sys/capability.h $(FAKEROOT)$(INCDIR)/sys
- install -m 0644 libcap.pc $(FAKEROOT)$(PKGCONFIGDIR)/libcap.pc
+ install -m 0644 $(LIBTITLE).pc $(FAKEROOT)$(PKGCONFIGDIR)/$(LIBTITLE).pc
include/sys/psx_syscall.h: ../psx/psx_syscall.h
rm -f $@
ln -s ../../../psx/psx_syscall.h $@
-install-common-psx: install-common libpsx.pc include/sys/psx_syscall.h
+install-common-psx: install-common $(PSXTITLE).pc include/sys/psx_syscall.h
install -m 0644 include/sys/psx_syscall.h $(FAKEROOT)$(INCDIR)/sys
- install -m 0644 libpsx.pc $(FAKEROOT)$(PKGCONFIGDIR)/libpsx.pc
+ install -m 0644 $(PSXTITLE).pc $(FAKEROOT)$(PKGCONFIGDIR)/$(PSXTITLE).pc
install-common:
mkdir -p -m 0755 $(FAKEROOT)$(INCDIR)/sys
@@ -182,8 +214,9 @@ install-common:
clean:
$(LOCALCLEAN)
- rm -f $(CAPOBJS) $(CAPLIBNAME)* $(STACAPLIBNAME) libcap.pc
- rm -f $(PSXOBJS) $(PSXLIBNAME)* $(STAPSXLIBNAME) libpsx.pc
+ rm -f $(CAPOBJS) $(CAPLIBNAME)* $(STACAPLIBNAME) $(LIBTITLE).pc
+ rm -f $(PSXOBJS) $(PSXLIBNAME)* $(STAPSXLIBNAME) $(PSXTITLE).pc
rm -f cap_names.h cap_names.list.h _makenames $(GPERF_OUTPUT) cap_test
rm -f include/sys/psx_syscall.h
+ rm -f $(CAPMAGICOBJ) $(PSXMAGICOBJ) empty loader.txt
cd include/sys && $(LOCALCLEAN)
diff --git a/libcap/empty.c b/libcap/empty.c
new file mode 100644
index 0000000..0314ff1
--- /dev/null
+++ b/libcap/empty.c
@@ -0,0 +1 @@
+int main(int argc, char **argv) { return 0; }
diff --git a/libcap/execable.c b/libcap/execable.c
new file mode 100644
index 0000000..be18914
--- /dev/null
+++ b/libcap/execable.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include "execable.h"
+
+SO_MAIN(int argc, char **argv)
+{
+ const char *cmd = "This library";
+ if (argv != NULL) {
+ cmd = argv[0];
+ }
+ printf("%s is the shared library version: " LIBRARY_VERSION ".\n"
+ "See the License file for distribution information.\n"
+ "More information on this library is available from:\n"
+ "\n"
+ " https://sites.google.com/site/fullycapable/\n", cmd);
+}
diff --git a/libcap/execable.h b/libcap/execable.h
new file mode 100644
index 0000000..391245d
--- /dev/null
+++ b/libcap/execable.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2021 Andrew G. Morgan <morgan@kernel.org>
+ *
+ * Some header magic to help make a shared object run-able as a stand
+ * alone executable binary.
+ *
+ * This is a slightly more sophisticated implementation than the
+ * answer I posted here:
+ *
+ * https://stackoverflow.com/a/68339111/14760867
+ *
+ * Compile your shared library with:
+ *
+ * -DDL_LOADER="\"ld-linux...\"" (loader for your target system)
+ * ...
+ * --entry=__so_start
+ */
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __EXECABLE_H
+#error "only inlcude execable.h once"
+#endif
+#define __EXECABLE_H
+
+const char __execable_dl_loader[] __attribute((section(".interp"))) =
+ SHARED_LOADER ;
+
+static void __execable_parse_args(int *argc_p, char ***argv_p)
+{
+ int argc = 0;
+ char **argv = NULL;
+ FILE *f = fopen("/proc/self/cmdline", "rb");
+ if (f != NULL) {
+ char *mem = NULL, *p;
+ size_t size = 4, offset;
+ for (offset=0; ; size *= 2) {
+ mem = realloc(mem, size+1);
+ if (mem == NULL) {
+ perror("unable to parse arguments");
+ exit(1);
+ }
+ offset += fread(mem+offset, 1, size-offset, f);
+ if (offset < size) {
+ size = offset;
+ mem[size] = '\0';
+ break;
+ }
+ }
+ fclose(f);
+ for (argc=1, p=mem+size-2; p >= mem; p--) {
+ argc += (*p == '\0');
+ }
+ argv = calloc(argc+1, sizeof(char *));
+ if (argv == NULL) {
+ perror("failed to allocate memory for argv");
+ exit(1);
+ }
+ for (p=mem, argc=0, offset=0; offset < size; argc++) {
+ argv[argc] = mem+offset;
+ offset += strlen(mem+offset)+1;
+ }
+ }
+ *argc_p = argc;
+ *argv_p = argv;
+}
+
+/*
+ * Note, to avoid any runtime confusion, SO_MAIN is a void static
+ * function.
+ */
+
+#define SO_MAIN \
+static void __execable_main(int, char**); \
+extern void __so_start(void); \
+void __so_start(void) \
+{ \
+ int argc; \
+ char **argv; \
+ __execable_parse_args(&argc, &argv); \
+ __execable_main(argc, argv); \
+ exit(0); \
+} \
+static void __execable_main