Browse Source

add support for init/finit (constructors and destructors)

this is mainly in hopes of supporting c++ (not yet possible for other
reasons) but will also help applications/libraries which use (and more
often, abuse) the gcc __attribute__((__constructor__)) feature in "C"
code.

x86_64 and arm versions of the new startup asm are untested and may
have minor problems.
Rich Felker 13 years ago
parent
commit
4ce3cb5cdd
10 changed files with 75 additions and 7 deletions
  1. 5 2
      crt/arm/crt1.s
  2. 7 0
      crt/arm/crti.s
  3. 9 0
      crt/arm/crtn.s
  4. 6 2
      crt/i386/crt1.s
  5. 7 0
      crt/i386/crti.s
  6. 5 0
      crt/i386/crtn.s
  7. 5 3
      crt/x86_64/crt1.s
  8. 7 0
      crt/x86_64/crti.s
  9. 5 0
      crt/x86_64/crtn.s
  10. 19 0
      src/ldso/dynlink.c

+ 5 - 2
crt/arm/crt1.s

@@ -1,13 +1,16 @@
+.weak _init
+.weak _fini
 .global _start
 .global _start
 _start:
 _start:
 	mov fp,#0
 	mov fp,#0
 	mov lr,#0
 	mov lr,#0
 	ldr a2,[sp],#4
 	ldr a2,[sp],#4
 	mov a3,sp
 	mov a3,sp
-	mov a4,#0
+	ldr a4,=_fini
 	str fp,[sp,#-4]!
 	str fp,[sp,#-4]!
 	str a1,[sp,#-4]!
 	str a1,[sp,#-4]!
-	str fp,[sp,#-4]!
+	str a4,[sp,#-4]!
+	ldr a4,=_init
 	ldr a1,=main
 	ldr a1,=main
 	bl __libc_start_main
 	bl __libc_start_main
 1:	b 1b
 1:	b 1b

+ 7 - 0
crt/arm/crti.s

@@ -0,0 +1,7 @@
+.section .init
+.global _init
+_init:
+
+.section .fini
+.global _fini
+_fini:

+ 9 - 0
crt/arm/crtn.s

@@ -0,0 +1,9 @@
+.section .init
+	tst lr,#1
+	moveq pc,lr
+	bx lr
+
+.section .fini
+	tst lr,#1
+	moveq pc,lr
+	bx lr

+ 6 - 2
crt/i386/crt1.s

@@ -1,3 +1,5 @@
+.weak _init
+.weak _fini
 .text
 .text
 .global _start
 .global _start
 _start:
 _start:
@@ -8,8 +10,10 @@ _start:
 	pushl %esp
 	pushl %esp
 	pushl %esp
 	pushl %esp
 	pushl %edx
 	pushl %edx
-	pushl %ebp
-	pushl %ebp
+	call 1f
+1:	addl $[_fini-.],(%esp)
+	call 1f
+1:	addl $[_init-.],(%esp)
 	pushl %eax
 	pushl %eax
 	pushl %ecx
 	pushl %ecx
 	call 1f
 	call 1f

+ 7 - 0
crt/i386/crti.s

@@ -0,0 +1,7 @@
+.section .init
+.global _init
+_init:
+
+.section .fini
+.global _fini
+_fini:

+ 5 - 0
crt/i386/crtn.s

@@ -0,0 +1,5 @@
+.section .init
+	ret
+
+.section .fini
+	ret

+ 5 - 3
crt/x86_64/crt1.s

@@ -1,4 +1,6 @@
 /* Written 2011 Nicholas J. Kain, released as Public Domain */
 /* Written 2011 Nicholas J. Kain, released as Public Domain */
+.weak _init
+.weak _fini
 .text
 .text
 .global _start
 .global _start
 _start:
 _start:
@@ -9,8 +11,8 @@ _start:
 	andq $-16,%rsp  /* align stack pointer */
 	andq $-16,%rsp  /* align stack pointer */
 	push %rax       /* 8th arg: glibc ABI compatible */
 	push %rax       /* 8th arg: glibc ABI compatible */
 	push %rsp       /* 7th arg: glibc ABI compatible */
 	push %rsp       /* 7th arg: glibc ABI compatible */
-	xor %r8,%r8     /* 5th arg: always 0 */
-	xor %rcx,%rcx   /* 4th arg: always 0 */
+	mov $_fini,%r8  /* 5th arg: fini/dtors function */
+	mov $_init,%rcx /* 4th arg: init/ctors function */
 	mov $main,%rdi  /* 1st arg: application entry ip */
 	mov $main,%rdi  /* 1st arg: application entry ip */
 	call __libc_start_main /* musl init will run the program */
 	call __libc_start_main /* musl init will run the program */
-.L0:	jmp .L0
+1:	jmp 1b

+ 7 - 0
crt/x86_64/crti.s

@@ -0,0 +1,7 @@
+.section .init
+.global _init
+_init:
+
+.section .fini
+.global _fini
+_fini:

+ 5 - 0
crt/x86_64/crtn.s

@@ -0,0 +1,5 @@
+.section .init
+	ret
+
+.section .fini
+	ret

+ 19 - 0
src/ldso/dynlink.c

@@ -49,6 +49,7 @@ struct dso
 	ino_t ino;
 	ino_t ino;
 	int global;
 	int global;
 	int relocated;
 	int relocated;
+	int constructed;
 	struct dso **deps;
 	struct dso **deps;
 	char *name;
 	char *name;
 	char buf[];
 	char buf[];
@@ -471,6 +472,20 @@ static size_t find_dyn(Phdr *ph, size_t cnt, size_t stride)
 	return 0;
 	return 0;
 }
 }
 
 
+static void do_init_fini(struct dso *p)
+{
+	size_t dyn[DYN_CNT] = {0};
+	for (; p; p=p->prev) {
+		if (p->constructed) return;
+		decode_vec(p->dynv, dyn, DYN_CNT);
+		if (dyn[0] & (1<<DT_FINI))
+			atexit((void (*)(void))(p->base + dyn[DT_FINI]));
+		if (dyn[0] & (1<<DT_INIT))
+			((void (*)(void))(p->base + dyn[DT_INIT]))();
+		p->constructed = 1;
+	}
+}
+
 void *__dynlink(int argc, char **argv)
 void *__dynlink(int argc, char **argv)
 {
 {
 	size_t *auxv, aux[AUX_CNT] = {0};
 	size_t *auxv, aux[AUX_CNT] = {0};
@@ -520,6 +535,7 @@ void *__dynlink(int argc, char **argv)
 	}
 	}
 	app->name = argv[0];
 	app->name = argv[0];
 	app->global = 1;
 	app->global = 1;
+	app->constructed = 1;
 	app->dynv = (void *)(app->base + find_dyn(
 	app->dynv = (void *)(app->base + find_dyn(
 		(void *)aux[AT_PHDR], aux[AT_PHNUM], aux[AT_PHENT]));
 		(void *)aux[AT_PHDR], aux[AT_PHNUM], aux[AT_PHENT]));
 	decode_dyn(app);
 	decode_dyn(app);
@@ -577,6 +593,9 @@ void *__dynlink(int argc, char **argv)
 	 * error. If the dynamic loader (dlopen) will not be used, free
 	 * error. If the dynamic loader (dlopen) will not be used, free
 	 * all memory used by the dynamic linker. */
 	 * all memory used by the dynamic linker. */
 	runtime = 1;
 	runtime = 1;
+
+	do_init_fini(tail);
+
 	if (!rtld_used) {
 	if (!rtld_used) {
 		free_all(head);
 		free_all(head);
 		free(sys_path);
 		free(sys_path);