Skip to content

Commit b790560

Browse files
committed
elfdeps: Add full multiarch deps support
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.
1 parent 8896e81 commit b790560

2 files changed

Lines changed: 133 additions & 14 deletions

File tree

fileattrs/elf.attr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
%__elf_provides %{_rpmconfigdir}/elfdeps --provides %{?__filter_GLIBC_PRIVATE:--filter-private}
2-
%__elf_requires %{_rpmconfigdir}/elfdeps --requires %{?__filter_GLIBC_PRIVATE:--filter-private}
1+
%__elf_provides %{_rpmconfigdir}/elfdeps --provides %{?__filter_GLIBC_PRIVATE:--filter-private} --biarch-deps %{?__multiarch_deps:--multiarch-deps}
2+
%__elf_requires %{_rpmconfigdir}/elfdeps --requires %{?__filter_GLIBC_PRIVATE:--filter-private} %{!?__multiarch_deps:--biarch-deps} %{?__multiarch_deps:--multiarch-deps}
33
%__elf_magic ^(setuid,? )?(setgid,? )?(sticky )?ELF (32|64)-bit.*$
44
%__elf_flags exeonly

tools/elfdeps.c

Lines changed: 131 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ int soname_only = 0;
1818
int fake_soname = 1;
1919
int filter_soname = 1;
2020
int require_interp = 0;
21+
int biarch_deps = 0;
22+
int multiarch_deps = 0;
2123

2224
typedef struct elfInfo_s {
2325
Elf *elf;
@@ -29,7 +31,8 @@ typedef struct elfInfo_s {
2931
int gotGNUHASH;
3032
char *soname;
3133
char *interp;
32-
const char *marker; /* elf class marker or NULL */
34+
const char *classmarker; /* elf class marker or NULL */
35+
const char *archmarker; /* elf arch marker or NULL */
3336

3437
ARGV_t requires;
3538
ARGV_t provides;
@@ -79,9 +82,9 @@ static int skipSoname(const char *soname)
7982
return 0;
8083
}
8184

82-
static const char *mkmarker(GElf_Ehdr *ehdr)
85+
static const char *mkclassmarker(GElf_Ehdr *ehdr)
8386
{
84-
const char *marker = NULL;
87+
const char *classmarker = NULL;
8588

8689
if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) {
8790
switch (ehdr->e_machine) {
@@ -90,11 +93,106 @@ static const char *mkmarker(GElf_Ehdr *ehdr)
9093
/* alpha doesn't traditionally have 64bit markers */
9194
break;
9295
default:
93-
marker = "(64bit)";
96+
classmarker = "(64bit)";
9497
break;
9598
}
9699
}
97-
return marker;
100+
return classmarker;
101+
}
102+
103+
static const char *mkarchmarker(GElf_Ehdr *ehdr)
104+
{
105+
char *archmarker = NULL;
106+
const char *elf_machine = NULL;
107+
const char *elf_endian = NULL;
108+
const char *elf_bitsize = NULL;
109+
110+
/* First the machine type... */
111+
switch (ehdr->e_machine) {
112+
case EM_SPARC:
113+
elf_machine = "sparc";
114+
break;
115+
case EM_386:
116+
case EM_X86_64:
117+
elf_machine = "x86";
118+
break;
119+
case EM_MIPS:
120+
elf_machine = "mips";
121+
break;
122+
case EM_PPC:
123+
case EM_PPC64:
124+
elf_machine = "ppc";
125+
break;
126+
case EM_S390:
127+
elf_machine = "s390";
128+
break;
129+
case EM_ARM:
130+
if ((ehdr->e_flags | EF_ARM_ABI_FLOAT_HARD) == EF_ARM_ABI_FLOAT_HARD)
131+
elf_machine = "armhfp";
132+
if ((ehdr->e_flags | EF_ARM_ABI_FLOAT_SOFT) == EF_ARM_ABI_FLOAT_SOFT)
133+
elf_machine = "armsfp";
134+
break;
135+
case EM_SPARCV9:
136+
elf_machine = "sparcv9";
137+
break;
138+
case EM_ALPHA:
139+
elf_machine = "alpha";
140+
break;
141+
case EM_AARCH64:
142+
elf_machine = "aarch";
143+
break;
144+
case EM_RISCV:
145+
elf_machine = "riscv";
146+
break;
147+
default:
148+
break;
149+
}
150+
151+
/* Then the endianness of the CPU... */
152+
switch (ehdr->e_ident[EI_DATA]) {
153+
case ELFDATA2LSB:
154+
elf_endian = "le";
155+
break;
156+
case ELFDATA2MSB:
157+
elf_endian = "be";
158+
break;
159+
default:
160+
break;
161+
}
162+
163+
/* Then the bit size of the CPU... */
164+
switch (ehdr->e_ident[EI_CLASS]) {
165+
case ELFCLASS64:
166+
elf_bitsize = "64";
167+
break;
168+
case ELFCLASS32:
169+
elf_bitsize = "32";
170+
break;
171+
default:
172+
break;
173+
}
174+
175+
/* Finally the arch marker! */
176+
switch (ehdr->e_machine) {
177+
case EM_MIPS:
178+
case EM_ARM:
179+
case EM_PPC64:
180+
rasprintf(&archmarker, "(%s%s-%s)", elf_machine, elf_endian, elf_bitsize);
181+
break;
182+
case EM_X86_64:
183+
/* This handling for x32 makes me weep inside... */
184+
if (ehdr->e_ident[EI_CLASS] == ELFCLASS32) {
185+
rasprintf(&archmarker, "(%s-%s-%s)", elf_machine, "64", "x32");
186+
} else {
187+
rasprintf(&archmarker, "(%s-%s)", elf_machine, elf_bitsize);
188+
}
189+
break;
190+
default:
191+
rasprintf(&archmarker, "(%s-%s)", elf_machine, elf_bitsize);
192+
break;
193+
}
194+
195+
return archmarker;
98196
}
99197

100198
static void addDep(ARGV_t *deps,
@@ -145,7 +243,10 @@ static void processVerDef(Elf_Scn *scn, GElf_Shdr *shdr, elfInfo *ei)
145243
auxoffset += aux->vda_next;
146244
continue;
147245
} else if (soname && !soname_only && !skipPrivate(s)) {
148-
addDep(&ei->provides, soname, s, ei->marker);
246+
if (multiarch_deps)
247+
addDep(&ei->provides, soname, s, ei->archmarker);
248+
if (biarch_deps)
249+
addDep(&ei->provides, soname, s, ei->classmarker);
149250
}
150251
}
151252

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

186287
if (ei->isExec && soname && !soname_only && !skipPrivate(s)) {
187-
addDep(&ei->requires, soname, s, ei->marker);
288+
if (multiarch_deps)
289+
addDep(&ei->requires, soname, s, ei->archmarker);
290+
if (biarch_deps)
291+
addDep(&ei->requires, soname, s, ei->classmarker);
188292
}
189293
auxoffset += aux->vna_next;
190294
}
@@ -224,8 +328,12 @@ static void processDynamic(Elf_Scn *scn, GElf_Shdr *shdr, elfInfo *ei)
224328
case DT_NEEDED:
225329
if (ei->isExec) {
226330
s = elf_strptr(ei->elf, shdr->sh_link, dyn->d_un.d_val);
227-
if (s)
228-
addDep(&ei->requires, s, NULL, ei->marker);
331+
if (s) {
332+
if (multiarch_deps)
333+
addDep(&ei->requires, s, NULL, ei->archmarker);
334+
if (biarch_deps)
335+
addDep(&ei->requires, s, NULL, ei->classmarker);
336+
}
229337
}
230338
break;
231339
}
@@ -298,7 +406,8 @@ static int processFile(const char *fn, int dtype)
298406
goto exit;
299407

300408
if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) {
301-
ei->marker = mkmarker(ehdr);
409+
ei->archmarker = mkarchmarker(ehdr);
410+
ei->classmarker = mkclassmarker(ehdr);
302411
ei->isDSO = (ehdr->e_type == ET_DYN);
303412
ei->isExec = (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH));
304413

@@ -324,8 +433,12 @@ static int processFile(const char *fn, int dtype)
324433
const char *bn = strrchr(fn, '/');
325434
ei->soname = rstrdup(bn ? bn + 1 : fn);
326435
}
327-
if (ei->soname)
328-
addDep(&ei->provides, ei->soname, NULL, ei->marker);
436+
if (ei->soname) {
437+
if (multiarch_deps)
438+
addDep(&ei->provides, ei->soname, NULL, ei->archmarker);
439+
if (biarch_deps)
440+
addDep(&ei->provides, ei->soname, NULL, ei->classmarker);
441+
}
329442
}
330443

331444
/* If requested and present, add dep for interpreter (ie dynamic linker) */
@@ -366,6 +479,8 @@ int main(int argc, char *argv[])
366479
{ "no-fake-soname", 0, POPT_ARG_VAL, &fake_soname, 0, NULL, NULL },
367480
{ "no-filter-soname", 0, POPT_ARG_VAL, &filter_soname, 0, NULL, NULL },
368481
{ "require-interp", 0, POPT_ARG_VAL, &require_interp, -1, NULL, NULL },
482+
{ "biarch-deps", 0, POPT_ARG_VAL, &biarch_deps, -1, NULL, NULL },
483+
{ "multiarch-deps", 0, POPT_ARG_VAL, &multiarch_deps, -1, NULL, NULL },
369484
POPT_AUTOHELP
370485
POPT_TABLEEND
371486
};
@@ -394,6 +509,10 @@ int main(int argc, char *argv[])
394509
}
395510
}
396511

512+
/* In the event that neither biarch nor multiarch modes are set, fallback to biarch */
513+
if (biarch_deps == 0 && multiarch_deps == 0)
514+
biarch_deps = 1;
515+
397516
poptFreeContext(optCon);
398517
return rc;
399518
}

0 commit comments

Comments
 (0)