diff options
author | Andrew G. Morgan <morgan@kernel.org> | 2021-07-12 16:32:56 -0700 |
---|---|---|
committer | Andrew G. Morgan <morgan@kernel.org> | 2021-07-12 21:23:32 -0700 |
commit | ee3b25c0a877fa74d1aec88f325ac45b09963c82 (patch) | |
tree | 67bf3458179a9e80a8055232f6891c989588531f | |
parent | f73a3691afe24fec86841eca43f5edcfbde875f3 (diff) | |
download | libcap-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.Rules | 1 | ||||
-rw-r--r-- | libcap/.gitignore | 4 | ||||
-rw-r--r-- | libcap/Makefile | 65 | ||||
-rw-r--r-- | libcap/empty.c | 1 | ||||
-rw-r--r-- | libcap/execable.c | 15 | ||||
-rw-r--r-- | libcap/execable.h | 84 |
6 files changed, 154 insertions, 16 deletions
@@ -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 |