summaryrefslogtreecommitdiff
path: root/lib/libc/internal
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/internal')
-rw-r--r--lib/libc/internal/Kbuild2
-rw-r--r--lib/libc/internal/init/Kbuild1
-rw-r--r--lib/libc/internal/init/vdso.c56
-rw-r--r--lib/libc/internal/libc_main.c40
4 files changed, 99 insertions, 0 deletions
diff --git a/lib/libc/internal/Kbuild b/lib/libc/internal/Kbuild
new file mode 100644
index 00000000..5015f987
--- /dev/null
+++ b/lib/libc/internal/Kbuild
@@ -0,0 +1,2 @@
+obj-y += init/
+obj-y += libc_main.o
diff --git a/lib/libc/internal/init/Kbuild b/lib/libc/internal/init/Kbuild
new file mode 100644
index 00000000..dd27261a
--- /dev/null
+++ b/lib/libc/internal/init/Kbuild
@@ -0,0 +1 @@
+obj-y += vdso.o
diff --git a/lib/libc/internal/init/vdso.c b/lib/libc/internal/init/vdso.c
new file mode 100644
index 00000000..f94401f6
--- /dev/null
+++ b/lib/libc/internal/init/vdso.c
@@ -0,0 +1,56 @@
+#include <asm/vdso.h>
+#include <elf.h>
+#include <string.h>
+#include <sys/auxv.h>
+
+void __init_vdso(void)
+{
+ Elf64_Ehdr *ehdr = (Elf64_Ehdr *)getauxval(AT_SYSINFO_EHDR);
+ Elf64_Phdr *phdr = (Elf64_Phdr *)(ehdr + ehdr->e_phoff);
+
+ for (int i = 0; i < ehdr->e_phnum; i++) {
+ Elf64_Dyn *dyn;
+ Elf64_Sym *symtab;
+ const char *strtab;
+
+ if (phdr[i].p_type == PT_DYNAMIC) {
+ Elf64_Sym *sym;
+
+ dyn = (Elf64_Dyn *)((char *)ehdr + phdr[i].p_offset);
+ symtab = 0;
+ strtab = 0;
+
+ while (dyn->d_tag != DT_NULL) {
+ if (dyn->d_tag == DT_STRTAB) {
+ strtab = (const char *)(ehdr + dyn->d_un.d_ptr);
+ } else if (dyn->d_tag == DT_SYMTAB) {
+ symtab = (Elf64_Sym *)(ehdr + dyn->d_un.d_ptr);
+ }
+
+ if (strtab && symtab) {
+ break;
+ }
+
+ dyn++;
+ }
+
+ sym = symtab;
+ while ((char *)sym < strtab) {
+ if (sym->st_name != 0 && sym->st_value != 0) {
+ const char *name = strtab + sym->st_name;
+
+ for (int i = 0; __vdso_symtab[i].name != 0; i++) {
+ if (strcmp(name, __vdso_symtab[i].name) == 0) {
+ __vdso_symtab[i].func = (void *)(ehdr + sym->st_value);
+ break;
+ }
+ }
+ }
+
+ sym = (Elf64_Sym *)((char *)sym + sizeof(Elf64_Sym));
+ }
+
+ break;
+ }
+ }
+}
diff --git a/lib/libc/internal/libc_main.c b/lib/libc/internal/libc_main.c
new file mode 100644
index 00000000..7ac15ab4
--- /dev/null
+++ b/lib/libc/internal/libc_main.c
@@ -0,0 +1,40 @@
+#include <libc.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/cdefs.h>
+
+extern void __init_vdso(void);
+
+struct libc __libc;
+char **environ;
+char *__progname;
+
+extern int main(int, char **, char **);
+
+__used void __libc_main(uintptr_t *rsp)
+{
+ char **argv;
+ size_t *auxv;
+ int argc;
+
+ argc = (int)(*rsp);
+ argv = (char **)(++rsp);
+
+ rsp += argc;
+
+ environ = (char **)(++rsp);
+ __progname = argv[0];
+
+ while (*rsp)
+ rsp++;
+
+ auxv = (size_t *)++rsp;
+
+ for (size_t i = 0; auxv[i]; i += 2)
+ __libc.auxv[auxv[i]] = auxv[i + 1];
+
+ __init_vdso();
+
+ exit(main(argc, argv, environ));
+}