Skip to content

Instantly share code, notes, and snippets.

@sorear
Created March 23, 2024 02:08
Show Gist options
  • Save sorear/f17038387b871ff0a16c74a85d987c05 to your computer and use it in GitHub Desktop.
Save sorear/f17038387b871ff0a16c74a85d987c05 to your computer and use it in GitHub Desktop.
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index 324aa859..91d91e1c 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -379,6 +379,17 @@ nomatch:
return (struct symdef){ 0 };
}
+static size_t get_leb128(unsigned char **buf, size_t sleb_uleb)
+{
+ size_t tmp = 0, shift = 0, byte;
+ do {
+ byte = *(*buf)++;
+ tmp += (byte - 128*(byte >= sleb_uleb)) << shift;
+ shift += 7;
+ } while (byte < 128);
+ return tmp;
+}
+
static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stride)
{
unsigned char *base = dso->base;
@@ -394,6 +405,8 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
size_t sym_val;
size_t tls_val;
size_t addend;
+ size_t offset_shift, rel_head;
+ unsigned char *relp;
int skip_relative = 0, reuse_addends = 0, save_slot = 0;
if (dso == &ldso) {
@@ -403,28 +416,53 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
skip_relative = 1;
}
+#ifndef DL_FDPIC
+ if (!stride) {
+ sym_index = addend = type = 0;
+ reloc_addr = laddr(dso, 0);
+ relp = (unsigned char*)rel;
+ rel_size = get_leb128(&relp, 128);
+ offset_shift = rel_size & 3;
+ rel_size >>= 2;
+ }
+#endif
+
for (; rel_size; rel+=stride, rel_size-=stride*sizeof(size_t)) {
- if (skip_relative && IS_RELATIVE(rel[1], dso->syms)) continue;
- type = R_TYPE(rel[1]);
- if (type == REL_NONE) continue;
- reloc_addr = laddr(dso, rel[0]);
-
- if (stride > 2) {
- addend = rel[2];
- } else if (type==REL_GOT || type==REL_PLT|| type==REL_COPY) {
- addend = 0;
- } else if (reuse_addends) {
- /* Save original addend in stage 2 where the dso
- * chain consists of just ldso; otherwise read back
- * saved addend since the inline one was clobbered. */
- if (head==&ldso)
- saved_addends[save_slot] = *reloc_addr;
- addend = saved_addends[save_slot++];
+#ifndef DL_FDPIC
+ if (!stride) {
+ rel_head = *relp++;
+ reloc_addr += rel_head >> (3 - offset_shift);
+ if (rel_head & 128) += (get_leb128(&relp, 128) - 128) << (5 + offset_shift);
+ if (rel_head & 1) sym_index += get_leb128(&relp, 64);
+ if (rel_head & 2) type += get_leb128(&relp, 64);
+ if (rel_head & 4) addend += get_leb128(&relp, 64);
+ rel_size--;
} else {
- addend = *reloc_addr;
- }
+#endif
+ if (skip_relative && IS_RELATIVE(rel[1], dso->syms)) continue;
+ type = R_TYPE(rel[1]);
+ if (type == REL_NONE) continue;
+ reloc_addr = laddr(dso, rel[0]);
+
+ if (stride > 2) {
+ addend = rel[2];
+ } else if (type==REL_GOT || type==REL_PLT|| type==REL_COPY) {
+ addend = 0;
+ } else if (reuse_addends) {
+ /* Save original addend in stage 2 where the dso
+ * chain consists of just ldso; otherwise read back
+ * saved addend since the inline one was clobbered. */
+ if (head==&ldso)
+ saved_addends[save_slot] = *reloc_addr;
+ addend = saved_addends[save_slot++];
+ } else {
+ addend = *reloc_addr;
+ }
- sym_index = R_SYM(rel[1]);
+ sym_index = R_SYM(rel[1]);
+#ifndef DL_FDPIC
+ }
+#endif
if (sym_index) {
sym = syms + sym_index;
name = strings + sym->st_name;
@@ -1421,6 +1459,8 @@ static void reloc_all(struct dso *p)
do_relocs(p, laddr(p, dyn[DT_RELA]), dyn[DT_RELASZ], 3);
if (!DL_FDPIC)
do_relr_relocs(p, laddr(p, dyn[DT_RELR]), dyn[DT_RELRSZ]);
+ if (dyn[DT_CRELSZ])
+ do_relocs(p, laddr(p, dyn[DT_CREL]), 0, 0);
if (head != &ldso && p->relro_start != p->relro_end) {
long ret = __syscall(SYS_mprotect, laddr(p, p->relro_start),
@@ -2083,7 +2123,8 @@ static void prepare_lazy(struct dso *p)
search_vec(p->dynv, &flags1, DT_FLAGS_1);
if (dyn[DT_BIND_NOW] || (dyn[DT_FLAGS] & DF_BIND_NOW) || (flags1 & DF_1_NOW))
return;
- n = dyn[DT_RELSZ]/2 + dyn[DT_RELASZ]/3 + dyn[DT_PLTRELSZ]/2 + 1;
+ n = dyn[DT_RELSZ]/2 + dyn[DT_RELASZ]/3 + dyn[DT_PLTRELSZ]/2 + dyn[DT_CRELSZ] + 1;
+
if (NEED_MIPS_GOT_RELOCS) {
size_t j=0; search_vec(p->dynv, &j, DT_MIPS_GOTSYM);
size_t i=0; search_vec(p->dynv, &i, DT_MIPS_SYMTABNO);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment