+/* Stage 1 of the dynamic linker is defined in dlstart.c. It calls the
+ * following stage 2 and stage 3 functions via primitive symbolic lookup
+ * since it does not have access to their addresses to begin with. */
+
+/* Stage 2 of the dynamic linker is called after relative relocations
+ * have been processed. It can make function calls to static functions
+ * and access string literals and static data, but cannot use extern
+ * symbols. Its job is to perform symbolic relocations on the dynamic
+ * linker itself, but some of the relocations performed may need to be
+ * replaced later due to copy relocations in the main program. */
+
+void __dls2(unsigned char *base, size_t *sp)
+{
+ Ehdr *ehdr = (void *)base;
+ ldso.base = base;
+ ldso.name = ldso.shortname = "libc.so";
+ ldso.global = 1;
+ ldso.phnum = ehdr->e_phnum;
+ ldso.phdr = (void *)(base + ehdr->e_phoff);
+ ldso.phentsize = ehdr->e_phentsize;
+ kernel_mapped_dso(&ldso);
+ decode_dyn(&ldso);
+
+ /* Prepare storage for to save clobbered REL addends so they
+ * can be reused in stage 3. There should be very few. If
+ * something goes wrong and there are a huge number, abort
+ * instead of risking stack overflow. */
+ size_t dyn[DYN_CNT];
+ decode_vec(ldso.dynv, dyn, DYN_CNT);
+ size_t *rel = (void *)(base+dyn[DT_REL]);
+ size_t rel_size = dyn[DT_RELSZ];
+ size_t symbolic_rel_cnt = 0;
+ apply_addends_to = rel;
+ for (; rel_size; rel+=2, rel_size-=2*sizeof(size_t))
+ if (!IS_RELATIVE(rel[1])) symbolic_rel_cnt++;
+ if (symbolic_rel_cnt >= ADDEND_LIMIT) a_crash();
+ size_t addends[symbolic_rel_cnt+1];
+ saved_addends = addends;
+
+ head = &ldso;
+ reloc_all(&ldso);
+
+ ldso.relocated = 0;
+
+ /* Call dynamic linker stage-3, __dls3, looking it up
+ * symbolically as a barrier against moving the address
+ * load across the above relocation processing. */
+ struct symdef dls3_def = find_sym(&ldso, "__dls3", 0);
+ ((stage3_func)(ldso.base+dls3_def.sym->st_value))(sp);
+}
+
+/* Stage 3 of the dynamic linker is called with the dynamic linker/libc
+ * fully functional. Its job is to load (if not already loaded) and
+ * process dependencies and relocations for the main application and
+ * transfer control to its entry point. */
+
+_Noreturn void __dls3(size_t *sp)