Skip to content

Commit

Permalink
elfdeps: Add full multiarch deps support
Browse files Browse the repository at this point in the history
This changes elfdeps to emit dependency strings that contain full
architecture names instead of just declaring whether something is
"64bit". This means that systems that allow more than two architectures
to be installed on the same computer will actually be able to resolve
library dependencies correctly.

This means that RPM dependencies would be compatible with system library
install schemes like Debian's, where libraries are installed into
subdirectories under "/usr/lib" that are named after the platform
triple. It also allows for multiarch installations where foreign
architecture packages are automatically relocated to be installed under
a system root target location (e.g. "/usr/<triple>/lib(64)") as is done in
distributions like Exherbo.

As part of this change, the legacy behavior is now encoded behind the
--biarch-deps flag, which is passed in for both Provides and Requires
by default.

This behavior can be enabled by passing --multiarch-deps or by setting
%__multiarch_deps to 1 in the spec or vendor configuration.

When setting %__multiarch_deps to 1 in the spec or vendor configuration,
biarch Provides are still generated to allow distributions to support
packages generated with the legacy ELF dependency generator behavior.
  • Loading branch information
Conan-Kudo committed Feb 3, 2020
1 parent 8896e81 commit f7ce837
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 14 deletions.
4 changes: 2 additions & 2 deletions fileattrs/elf.attr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
%__elf_provides %{_rpmconfigdir}/elfdeps --provides %{?__filter_GLIBC_PRIVATE:--filter-private}
%__elf_requires %{_rpmconfigdir}/elfdeps --requires %{?__filter_GLIBC_PRIVATE:--filter-private}
%__elf_provides %{_rpmconfigdir}/elfdeps --provides %{?__filter_GLIBC_PRIVATE:--filter-private} --biarch-deps %{?__multiarch_deps:--multiarch-deps}
%__elf_requires %{_rpmconfigdir}/elfdeps --requires %{?__filter_GLIBC_PRIVATE:--filter-private} %{!?__multiarch_deps:--biarch-deps} %{?__multiarch_deps:--multiarch-deps}
%__elf_magic ^(setuid,? )?(setgid,? )?(sticky )?ELF (32|64)-bit.*$
%__elf_flags exeonly
143 changes: 131 additions & 12 deletions tools/elfdeps.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ int soname_only = 0;
int fake_soname = 1;
int filter_soname = 1;
int require_interp = 0;
int biarch_deps = 0;
int multiarch_deps = 0;

typedef struct elfInfo_s {
Elf *elf;
Expand All @@ -29,7 +31,8 @@ typedef struct elfInfo_s {
int gotGNUHASH;
char *soname;
char *interp;
const char *marker; /* elf class marker or NULL */
const char *classmarker; /* elf class marker or NULL */
const char *archmarker; /* elf arch marker or NULL */

ARGV_t requires;
ARGV_t provides;
Expand Down Expand Up @@ -79,9 +82,9 @@ static int skipSoname(const char *soname)
return 0;
}

static const char *mkmarker(GElf_Ehdr *ehdr)
static const char *mkclassmarker(GElf_Ehdr *ehdr)
{
const char *marker = NULL;
const char *classmarker = NULL;

if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) {
switch (ehdr->e_machine) {
Expand All @@ -90,11 +93,106 @@ static const char *mkmarker(GElf_Ehdr *ehdr)
/* alpha doesn't traditionally have 64bit markers */
break;
default:
marker = "(64bit)";
classmarker = "(64bit)";
break;
}
}
return marker;
return classmarker;
}

static const char *mkarchmarker(GElf_Ehdr *ehdr)
{
char *archmarker = NULL;
const char *elf_machine = NULL;
const char *elf_endian = NULL;
const char *elf_bitsize = NULL;

/* First the machine type... */
switch (ehdr->e_machine) {
case EM_SPARC:
elf_machine = "sparc";
break;
case EM_386:
case EM_X86_64:
elf_machine = "x86";
break;
case EM_MIPS:
elf_machine = "mips";
break;
case EM_PPC:
case EM_PPC64:
elf_machine = "ppc";
break;
case EM_S390:
elf_machine = "s390";
break;
case EM_ARM:
if ((ehdr->e_flags & ~EF_ARM_ABI_FLOAT_HARD) == EF_ARM_ABI_FLOAT_HARD)
elf_machine = "armhfp";
if ((ehdr->e_flags & ~EF_ARM_ABI_FLOAT_SOFT) == EF_ARM_ABI_FLOAT_SOFT)
elf_machine = "armsfp";
break;
case EM_SPARCV9:
elf_machine = "sparcv9";
break;
case EM_ALPHA:
elf_machine = "alpha";
break;
case EM_AARCH64:
elf_machine = "aarch";
break;
case EM_RISCV:
elf_machine = "riscv";
break;
default:
break;
}

/* Then the endianness of the CPU... */
switch (ehdr->e_ident[EI_DATA]) {
case ELFDATA2LSB:
elf_endian = "le";
break;
case ELFDATA2MSB:
elf_endian = "be";
break;
default:
break;
}

/* Then the bit size of the CPU... */
switch (ehdr->e_ident[EI_CLASS]) {
case ELFCLASS64:
elf_bitsize = "64";
break;
case ELFCLASS32:
elf_bitsize = "32";
break;
default:
break;
}

/* Finally the arch marker! */
switch (ehdr->e_machine) {
case EM_MIPS:
case EM_ARM:
case EM_PPC64:
rasprintf(&archmarker, "(%s%s-%s)", elf_machine, elf_endian, elf_bitsize);
break;
case EM_X86_64:
/* This handling for x32 makes me weep inside... */
if (ehdr->e_ident[EI_CLASS] == ELFCLASS32) {
rasprintf(&archmarker, "(%s-%s-%s)", elf_machine, "64", "x32");
} else {
rasprintf(&archmarker, "(%s-%s)", elf_machine, elf_bitsize);
}
break;
default:
rasprintf(&archmarker, "(%s-%s)", elf_machine, elf_bitsize);
break;
}

return archmarker;
}

static void addDep(ARGV_t *deps,
Expand Down Expand Up @@ -145,7 +243,10 @@ static void processVerDef(Elf_Scn *scn, GElf_Shdr *shdr, elfInfo *ei)
auxoffset += aux->vda_next;
continue;
} else if (soname && !soname_only && !skipPrivate(s)) {
addDep(&ei->provides, soname, s, ei->marker);
if (multiarch_deps)
addDep(&ei->provides, soname, s, ei->archmarker);
if (biarch_deps)
addDep(&ei->provides, soname, s, ei->classmarker);
}
}

Expand Down Expand Up @@ -184,7 +285,10 @@ static void processVerNeed(Elf_Scn *scn, GElf_Shdr *shdr, elfInfo *ei)
break;

if (ei->isExec && soname && !soname_only && !skipPrivate(s)) {
addDep(&ei->requires, soname, s, ei->marker);
if (multiarch_deps)
addDep(&ei->requires, soname, s, ei->archmarker);
if (biarch_deps)
addDep(&ei->requires, soname, s, ei->classmarker);
}
auxoffset += aux->vna_next;
}
Expand Down Expand Up @@ -224,8 +328,12 @@ static void processDynamic(Elf_Scn *scn, GElf_Shdr *shdr, elfInfo *ei)
case DT_NEEDED:
if (ei->isExec) {
s = elf_strptr(ei->elf, shdr->sh_link, dyn->d_un.d_val);
if (s)
addDep(&ei->requires, s, NULL, ei->marker);
if (s) {
if (multiarch_deps)
addDep(&ei->requires, s, NULL, ei->archmarker);
if (biarch_deps)
addDep(&ei->requires, s, NULL, ei->classmarker);
}
}
break;
}
Expand Down Expand Up @@ -298,7 +406,8 @@ static int processFile(const char *fn, int dtype)
goto exit;

if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) {
ei->marker = mkmarker(ehdr);
ei->archmarker = mkarchmarker(ehdr);
ei->classmarker = mkclassmarker(ehdr);
ei->isDSO = (ehdr->e_type == ET_DYN);
ei->isExec = (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH));

Expand All @@ -324,8 +433,12 @@ static int processFile(const char *fn, int dtype)
const char *bn = strrchr(fn, '/');
ei->soname = rstrdup(bn ? bn + 1 : fn);
}
if (ei->soname)
addDep(&ei->provides, ei->soname, NULL, ei->marker);
if (ei->soname) {
if (multiarch_deps)
addDep(&ei->provides, ei->soname, NULL, ei->archmarker);
if (biarch_deps)
addDep(&ei->provides, ei->soname, NULL, ei->classmarker);
}
}

/* If requested and present, add dep for interpreter (ie dynamic linker) */
Expand Down Expand Up @@ -366,6 +479,8 @@ int main(int argc, char *argv[])
{ "no-fake-soname", 0, POPT_ARG_VAL, &fake_soname, 0, NULL, NULL },
{ "no-filter-soname", 0, POPT_ARG_VAL, &filter_soname, 0, NULL, NULL },
{ "require-interp", 0, POPT_ARG_VAL, &require_interp, -1, NULL, NULL },
{ "biarch-deps", 0, POPT_ARG_VAL, &biarch_deps, -1, NULL, NULL },
{ "multiarch-deps", 0, POPT_ARG_VAL, &multiarch_deps, -1, NULL, NULL },
POPT_AUTOHELP
POPT_TABLEEND
};
Expand Down Expand Up @@ -394,6 +509,10 @@ int main(int argc, char *argv[])
}
}

/* In the event that neither biarch nor multiarch modes are set, fallback to biarch */
if (biarch_deps == 0 && multiarch_deps == 0)
biarch_deps = 1;

poptFreeContext(optCon);
return rc;
}

0 comments on commit f7ce837

Please sign in to comment.