From 81693617a258a5e56ffc57ff6c37755e98beda18 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 7 Apr 2021 23:55:21 +0200 Subject: [PATCH 1/4] lib: add DT_REL to elf_py/clippy ELF code ARM (32-bit) needs DT_REL... and here I was hoping I could avoid the trouble. Fixes: #8355 Signed-off-by: David Lamparter --- lib/elf_py.c | 120 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 99 insertions(+), 21 deletions(-) diff --git a/lib/elf_py.c b/lib/elf_py.c index d26e443b82..b47aa3d795 100644 --- a/lib/elf_py.c +++ b/lib/elf_py.c @@ -1032,7 +1032,7 @@ static char *elfdata_strptr(Elf_Data *data, size_t offset) static void elffile_add_dynreloc(struct elffile *w, Elf_Data *reldata, size_t entries, Elf_Data *symdata, - Elf_Data *strdata) + Elf_Data *strdata, Elf_Type typ) { size_t i; @@ -1041,12 +1041,59 @@ static void elffile_add_dynreloc(struct elffile *w, Elf_Data *reldata, size_t symidx; GElf_Rela *rela; GElf_Sym *sym; + GElf_Addr rel_offs = 0; relw = (struct elfreloc *)typeobj_elfreloc.tp_alloc( &typeobj_elfreloc, 0); relw->ef = w; - rela = relw->rela = gelf_getrela(reldata, i, &relw->_rela); + if (typ == ELF_T_REL) { + GElf_Rel _rel, *rel; + GElf_Addr offs; + + rel = gelf_getrel(reldata, i, &_rel); + relw->rela = &relw->_rela; + relw->rela->r_offset = rel->r_offset; + relw->rela->r_info = rel->r_info; + relw->rela->r_addend = 0; + relw->relative = true; + + /* REL uses the pointer contents itself instead of the + * RELA addend field :( ... theoretically this could + * be some weird platform specific encoding, but since + * we only care about data relocations it should + * always be a pointer... + */ + if (elffile_virt2file(w, rel->r_offset, &offs)) { + Elf_Data *ptr, *conv; + GElf_Addr tmp; + Elf_Data mem = { + .d_buf = (void *)&tmp, + .d_type = ELF_T_ADDR, + .d_version = EV_CURRENT, + .d_size = sizeof(tmp), + .d_off = 0, + .d_align = 0, + }; + + ptr = elf_getdata_rawchunk(w->elf, offs, + w->elfclass / 8, + ELF_T_ADDR); + + conv = gelf_xlatetom(w->elf, &mem, ptr, + w->mmap[EI_DATA]); + if (conv) { + memcpy(&rel_offs, conv->d_buf, + conv->d_size); + + relw->relative = false; + relw->rela->r_addend = rel_offs; + } + } + } else + relw->rela = gelf_getrela(reldata, i, &relw->_rela); + + rela = relw->rela; symidx = relw->symidx = GELF_R_SYM(rela->r_info); sym = relw->sym = gelf_getsym(symdata, symidx, &relw->_sym); if (sym) { @@ -1062,9 +1109,16 @@ static void elffile_add_dynreloc(struct elffile *w, Elf_Data *reldata, relw->st_value = 0; } - debugf("dynreloc @ %016llx sym %5llu %016llx %s\n", - (long long)rela->r_offset, (unsigned long long)symidx, - (long long)rela->r_addend, relw->symname); + if (typ == ELF_T_RELA) + debugf("dynrela @ %016llx sym %5llu %016llx %s\n", + (long long)rela->r_offset, + (unsigned long long)symidx, + (long long)rela->r_addend, relw->symname); + else + debugf("dynrel @ %016llx sym %5llu (%016llx) %s\n", + (long long)rela->r_offset, + (unsigned long long)symidx, + (unsigned long long)rel_offs, relw->symname); elfrelocs_add(&w->dynrelocs, relw); } @@ -1166,8 +1220,10 @@ static PyObject *elffile_load(PyTypeObject *type, PyObject *args, Elf_Data *dyndata = elf_getdata_rawchunk(w->elf, phdr->p_offset, phdr->p_filesz, ELF_T_DYN); - GElf_Addr dynrela = 0, symtab = 0, strtab = 0; - size_t dynrelasz = 0, dynrelaent = 0, strsz = 0; + GElf_Addr dynrela = 0, dynrel = 0, symtab = 0, strtab = 0; + size_t dynrelasz = 0, dynrelaent = 0; + size_t dynrelsz = 0, dynrelent = 0; + size_t strsz = 0; GElf_Dyn _dyn, *dyn; for (size_t j = 0;; j++) { @@ -1198,16 +1254,20 @@ static PyObject *elffile_load(PyTypeObject *type, PyObject *args, dynrelaent = dyn->d_un.d_val; break; + case DT_REL: + dynrel = dyn->d_un.d_ptr; + break; case DT_RELSZ: - if (dyn->d_un.d_val) - fprintf(stderr, - "WARNING: ignoring non-empty DT_REL!\n"); + dynrelsz = dyn->d_un.d_val; + break; + case DT_RELENT: + dynrelent = dyn->d_un.d_val; break; } } GElf_Addr offset; - Elf_Data *symdata = NULL, *strdata = NULL, *reladata = NULL; + Elf_Data *symdata = NULL, *strdata = NULL; if (elffile_virt2file(w, symtab, &offset)) symdata = elf_getdata_rawchunk(w->elf, offset, @@ -1217,19 +1277,37 @@ static PyObject *elffile_load(PyTypeObject *type, PyObject *args, strdata = elf_getdata_rawchunk(w->elf, offset, strsz, ELF_T_BYTE); - if (!dynrela || !dynrelasz || !dynrelaent) - continue; + size_t c; - if (!elffile_virt2file(w, dynrela, &offset)) - continue; + if (dynrela && dynrelasz && dynrelaent + && elffile_virt2file(w, dynrela, &offset)) { + Elf_Data *reladata = NULL; - debugf("dynrela @%llx/%llx+%llx\n", (long long)dynrela, - (long long)offset, (long long)dynrelasz); + debugf("dynrela @%llx/%llx+%llx\n", (long long)dynrela, + (long long)offset, (long long)dynrelasz); - reladata = elf_getdata_rawchunk(w->elf, offset, dynrelasz, - ELF_T_RELA); - elffile_add_dynreloc(w, reladata, dynrelasz / dynrelaent, - symdata, strdata); + reladata = elf_getdata_rawchunk(w->elf, offset, + dynrelasz, ELF_T_RELA); + + c = dynrelasz / dynrelaent; + elffile_add_dynreloc(w, reladata, c, symdata, strdata, + ELF_T_RELA); + } + + if (dynrel && dynrelsz && dynrelent + && elffile_virt2file(w, dynrel, &offset)) { + Elf_Data *reldata = NULL; + + debugf("dynrel @%llx/%llx+%llx\n", (long long)dynrel, + (long long)offset, (long long)dynrelsz); + + reldata = elf_getdata_rawchunk(w->elf, offset, dynrelsz, + ELF_T_REL); + + c = dynrelsz / dynrelent; + elffile_add_dynreloc(w, reldata, c, symdata, strdata, + ELF_T_REL); + } } #endif From b17f302b2015c0e8d97a0ff3f023b83830a6ec6f Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 8 Apr 2021 00:00:27 +0200 Subject: [PATCH 2/4] python: fix 32-bit pointers in xrelfo container_of This was mistakenly using the host platform's pointer size rather than the ELF file's. Only noticeable when cross compiling... Signed-off-by: David Lamparter --- python/clippy/elf.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/clippy/elf.py b/python/clippy/elf.py index 4ed334f0c4..02cb2e38b3 100644 --- a/python/clippy/elf.py +++ b/python/clippy/elf.py @@ -162,7 +162,10 @@ class ELFDissectData(object): for field in parent._efields[self.elfclass]: if field[0] == fieldname: break - offset += struct.calcsize(field[1]) + spec = field[1] + if spec == 'P': + spec = 'I' if self.elfclass == 32 else 'Q' + offset += struct.calcsize(spec) else: raise AttributeError('%r not found in %r.fields' % (fieldname, parent)) From 636aad94735aff8aeec911bca4c32f4e5e48d77c Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 9 Apr 2021 19:56:05 +0200 Subject: [PATCH 3/4] build: don't link pathd/path_main.c twice Can't have things duplicate in libpath.a and pathd directly, they'll crash into eath other on linking. No idea why this doesn't error out in our CI builds, but it definitely breaks LTO builds. Signed-off-by: David Lamparter --- pathd/subdir.am | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pathd/subdir.am b/pathd/subdir.am index b4501214bf..fdc08e9e97 100644 --- a/pathd/subdir.am +++ b/pathd/subdir.am @@ -22,7 +22,6 @@ pathd_libpath_a_SOURCES = \ pathd/path_cli.c \ pathd/path_debug.c \ pathd/path_errors.c \ - pathd/path_main.c \ pathd/path_nb.c \ pathd/path_nb_config.c \ pathd/path_nb_state.c \ @@ -50,7 +49,9 @@ noinst_HEADERS += \ pathd/pathd.h \ # end -pathd_pathd_SOURCES = pathd/path_main.c +pathd_pathd_SOURCES = \ + pathd/path_main.c \ + # end nodist_pathd_pathd_SOURCES = \ yang/frr-pathd.yang.c \ # end From 0490ce41c133f9a801f36668dd58b326ec72a7aa Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 9 Apr 2021 20:38:56 +0200 Subject: [PATCH 4/4] pceplib: add missing endian.h and config.h endian.h supplies be*toh() and htobe*() functions. This fixes the build on musl libc. On other systems it seems endian.h comes in transitively from some other header. (Also, all .c files should have config.h or zebra.h as the first include, even if it works without that it's b0rked and only works due to luck.) Tested-by: Lucian Cristian Signed-off-by: David Lamparter --- pceplib/pcep_msg_tlvs_encoding.c | 9 +++++++++ pceplib/test/pcep_msg_tlvs_test.c | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/pceplib/pcep_msg_tlvs_encoding.c b/pceplib/pcep_msg_tlvs_encoding.c index 967f138143..37f3353f76 100644 --- a/pceplib/pcep_msg_tlvs_encoding.c +++ b/pceplib/pcep_msg_tlvs_encoding.c @@ -25,6 +25,15 @@ * Encoding and decoding for PCEP Object TLVs. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __FreeBSD__ +#include +#else +#include +#endif /* __FreeBSD__ */ #include #include diff --git a/pceplib/test/pcep_msg_tlvs_test.c b/pceplib/test/pcep_msg_tlvs_test.c index 6b650f6823..57e1d16e91 100644 --- a/pceplib/test/pcep_msg_tlvs_test.c +++ b/pceplib/test/pcep_msg_tlvs_test.c @@ -21,6 +21,15 @@ */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __FreeBSD__ +#include +#else +#include +#endif /* __FreeBSD__ */ #include #include