• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Andrew G. Morgan <morgan@kernel.org>
3  *
4  * Some header magic to help make a shared object run-able as a stand
5  * alone executable binary.
6  *
7  * This is a slightly more sophisticated implementation than the
8  * answer I posted here:
9  *
10  *    https://stackoverflow.com/a/68339111/14760867
11  *
12  * Compile your shared library with:
13  *
14  *   -DSHARED_LOADER="\"ld-linux...\"" (loader for your target system)
15  *   ...
16  *   --entry=__so_start
17  */
18 #include <stdlib.h>
19 #include <string.h>
20 
21 #ifdef __EXECABLE_H
22 #error "only include execable.h once"
23 #endif
24 #define __EXECABLE_H
25 
26 const char __execable_dl_loader[] __attribute((section(".interp"))) =
27     SHARED_LOADER ;
28 
__execable_parse_args(int * argc_p,char *** argv_p)29 static void __execable_parse_args(int *argc_p, char ***argv_p)
30 {
31     int argc = 0;
32     char **argv = NULL;
33     FILE *f = fopen("/proc/self/cmdline", "rb");
34     if (f != NULL) {
35 	char *mem = NULL, *p;
36 	size_t size = 32, offset;
37 	for (offset=0; ; size *= 2) {
38 	    char *new_mem = realloc(mem, size+1);
39 	    if (new_mem == NULL) {
40 		perror("unable to parse arguments");
41 		if (mem != NULL) {
42 		    free(mem);
43 		}
44 		exit(1);
45 	    }
46 	    mem = new_mem;
47 	    offset += fread(mem+offset, 1, size-offset, f);
48 	    if (offset < size) {
49 		size = offset;
50 		mem[size] = '\0';
51 		break;
52 	    }
53 	}
54 	fclose(f);
55 	for (argc=1, p=mem+size-2; p >= mem; p--) {
56 	    argc += (*p == '\0');
57 	}
58 	argv = calloc(argc+1, sizeof(char *));
59 	if (argv == NULL) {
60 	    perror("failed to allocate memory for argv");
61 	    free(mem);
62 	    exit(1);
63 	}
64 	for (p=mem, argc=0, offset=0; offset < size; argc++) {
65 	    argv[argc] = mem+offset;
66 	    offset += strlen(mem+offset)+1;
67 	}
68     }
69     *argc_p = argc;
70     *argv_p = argv;
71 }
72 
73 /*
74  * Note, to avoid any runtime confusion, SO_MAIN is a void static
75  * function.
76  */
77 
78 #define SO_MAIN						        \
79 static void __execable_main(int, char**);                       \
80 extern void __so_start(void);		                	\
81 void __so_start(void)                                           \
82 {                                                               \
83     int argc;                                                   \
84     char **argv;                                                \
85     __execable_parse_args(&argc, &argv);                        \
86     __execable_main(argc, argv);				\
87     if (argc != 0) {                                            \
88 	free(argv[0]);                                          \
89 	free(argv);                                             \
90     }                                                           \
91     exit(0);                                                    \
92 }                                                               \
93 static void __execable_main
94