Skip to content

Commit d0c8fc9

Browse files
committed
Provide an option to use libtool version in elfdeps.c
1 parent c54b921 commit d0c8fc9

File tree

1 file changed

+81
-10
lines changed

1 file changed

+81
-10
lines changed

tools/elfdeps.c

+81-10
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@
99
#include <popt.h>
1010
#include <gelf.h>
1111

12+
#include <link.h>
13+
#include <dlfcn.h>
14+
1215
#include <rpm/rpmstring.h>
1316
#include <rpm/argv.h>
1417

18+
int libtool_version_fallback = 0;
1519
int soname_only = 0;
1620
int fake_soname = 1;
1721
int filter_soname = 1;
@@ -33,6 +37,53 @@ typedef struct elfInfo_s {
3337
ARGV_t provides;
3438
} elfInfo;
3539

40+
/*
41+
* If filename contains ".so" followed by a version number, return
42+
* a copy of the version number.
43+
*/
44+
static char *getLibtoolVer(const char *filename)
45+
{
46+
const char *so;
47+
int found_digit, found_dot = 0;
48+
// Start from the end of the string. Verify that it ends with
49+
// numbers and dots, preceded by ".so.".
50+
so = filename + strlen(filename);
51+
while (so > filename+2) {
52+
if (*so == '.') {
53+
found_dot++;
54+
so--;
55+
continue;
56+
} else if (strchr("0123456789", *so)) {
57+
found_digit++;
58+
so--;
59+
continue;
60+
} else if (strncmp(so-2, ".so.", 4) == 0) {
61+
so+=2;
62+
if (found_digit && found_dot > 1) {
63+
return strdup(so);
64+
}
65+
break;
66+
} else {
67+
return NULL;
68+
}
69+
}
70+
return NULL;
71+
}
72+
73+
static char *getLibtoolVerFromShLink(const char *filename)
74+
{
75+
void *dl_handle;
76+
struct link_map *linkmap;
77+
char *version = NULL;
78+
dl_handle = dlmopen(LM_ID_NEWLM, filename, RTLD_LAZY);
79+
if (dl_handle == NULL) return NULL;
80+
if (dlinfo(dl_handle, RTLD_DI_LINKMAP, &linkmap) != -1) {
81+
version = getLibtoolVer(linkmap->l_name);
82+
}
83+
dlclose(dl_handle);
84+
return version;
85+
}
86+
3687
/*
3788
* Rough soname sanity filtering: all sane soname's dependencies need to
3889
* contain ".so", and normal linkable libraries start with "lib",
@@ -96,14 +147,21 @@ static const char *mkmarker(GElf_Ehdr *ehdr)
96147
}
97148

98149
static void addDep(ARGV_t *deps,
99-
const char *soname, const char *ver, const char *marker)
150+
const char *soname, const char *ver, const char *marker,
151+
const char *compare_op, const char *fallback_ver)
100152
{
101153
char *dep = NULL;
102154

103155
if (skipSoname(soname))
104156
return;
105157

106-
if (ver || marker) {
158+
if (compare_op && fallback_ver) {
159+
// when versioned symbols aren't available, the libtool version
160+
// might be used to generate a minimum dependency version.
161+
rasprintf(&dep,
162+
"%s()%s %s %s", soname, marker ? marker : "",
163+
compare_op, fallback_ver);
164+
} else if (ver || marker) {
107165
rasprintf(&dep,
108166
"%s(%s)%s", soname, ver ? ver : "", marker ? marker : "");
109167
}
@@ -143,10 +201,10 @@ static void processVerDef(Elf_Scn *scn, GElf_Shdr *shdr, elfInfo *ei)
143201
auxoffset += aux->vda_next;
144202
continue;
145203
} else if (soname && !soname_only) {
146-
addDep(&ei->provides, soname, s, ei->marker);
204+
addDep(&ei->provides, soname, s, ei->marker, NULL, NULL);
147205
}
148206
}
149-
207+
150208
}
151209
}
152210
rfree(soname);
@@ -182,7 +240,7 @@ static void processVerNeed(Elf_Scn *scn, GElf_Shdr *shdr, elfInfo *ei)
182240
break;
183241

184242
if (genRequires(ei) && soname && !soname_only) {
185-
addDep(&ei->requires, soname, s, ei->marker);
243+
addDep(&ei->requires, soname, s, ei->marker, NULL, NULL);
186244
}
187245
auxoffset += aux->vna_next;
188246
}
@@ -222,8 +280,14 @@ static void processDynamic(Elf_Scn *scn, GElf_Shdr *shdr, elfInfo *ei)
222280
case DT_NEEDED:
223281
if (genRequires(ei)) {
224282
s = elf_strptr(ei->elf, shdr->sh_link, dyn->d_un.d_val);
225-
if (s)
226-
addDep(&ei->requires, s, NULL, ei->marker);
283+
if (s) {
284+
char *libtool_ver = NULL;
285+
if (libtool_version_fallback) {
286+
libtool_ver = getLibtoolVerFromShLink(s);
287+
}
288+
addDep(&ei->requires, s, NULL, ei->marker, ">=", libtool_ver);
289+
free(libtool_ver);
290+
}
227291
}
228292
break;
229293
}
@@ -322,8 +386,14 @@ static int processFile(const char *fn, int dtype)
322386
const char *bn = strrchr(fn, '/');
323387
ei->soname = rstrdup(bn ? bn + 1 : fn);
324388
}
325-
if (ei->soname)
326-
addDep(&ei->provides, ei->soname, NULL, ei->marker);
389+
if (ei->soname) {
390+
char *libtool_ver = NULL;
391+
if (libtool_version_fallback) {
392+
libtool_ver = getLibtoolVer(fn);
393+
}
394+
addDep(&ei->provides, ei->soname, NULL, ei->marker, "=", libtool_ver);
395+
free(libtool_ver);
396+
}
327397
}
328398

329399
/* If requested and present, add dep for interpreter (ie dynamic linker) */
@@ -359,11 +429,12 @@ int main(int argc, char *argv[])
359429
struct poptOption opts[] = {
360430
{ "provides", 'P', POPT_ARG_VAL, &provides, -1, NULL, NULL },
361431
{ "requires", 'R', POPT_ARG_VAL, &requires, -1, NULL, NULL },
432+
{ "libtool-version-fallback", 0, POPT_ARG_VAL, &libtool_version_fallback, -1, NULL, NULL },
362433
{ "soname-only", 0, POPT_ARG_VAL, &soname_only, -1, NULL, NULL },
363434
{ "no-fake-soname", 0, POPT_ARG_VAL, &fake_soname, 0, NULL, NULL },
364435
{ "no-filter-soname", 0, POPT_ARG_VAL, &filter_soname, 0, NULL, NULL },
365436
{ "require-interp", 0, POPT_ARG_VAL, &require_interp, -1, NULL, NULL },
366-
POPT_AUTOHELP
437+
POPT_AUTOHELP
367438
POPT_TABLEEND
368439
};
369440

0 commit comments

Comments
 (0)