bin/124906: [patch] teach /usr/bin/ldd about 32 bit objects on a 64
bit architecture
Edwin Groothuis
edwin at mavetju.org
Mon Jun 23 14:30:08 UTC 2008
>Number: 124906
>Category: bin
>Synopsis: [patch] teach /usr/bin/ldd about 32 bit objects on a 64 bit architecture
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Mon Jun 23 14:30:01 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator: Edwin Groothuis
>Release: FreeBSD 7.0-RELEASE-p1 i386
>Organization:
>Environment:
System: FreeBSD k7.mavetju 7.0-RELEASE-p1 FreeBSD 7.0-RELEASE-p1 #2: Wed May 28 08:12:56 EST 2008 edwin at k7.mavetju:/usr/src/sys/i386/compile/k7 i386
>Description:
The ldd utility of a 64 bit architecture doesn't work with 32 bit objects.
[/] root at ed-exigent>uname -a
FreeBSD ed-exigent.barnet.com.au 6.3-RELEASE-p1 FreeBSD 6.3-RELEASE-p1 #0: Wed Feb 13 00:11:33 UTC 2008 root at amd64-builder.daemonology.net:/usr/obj/usr/src/sys/SMP amd64
[/] root at ed-exigent>ldd `which httpd`
ldd: /usr/local/sbin/httpd: can't read program header
ldd: /usr/local/sbin/httpd: not a dynamic executable
But...
[/] root at ed-exigent>LD_32_TRACE_LOADED_OBJECTS==1 `which httpd`
libm.so.4 => /lib32//libm.so.4 (0x280c8000)
libaprutil-1.so.2 => /usr/local/lib/libaprutil-1.so.2 (0x280de000)
libexpat.so.6 => /usr/local/lib/libexpat.so.6 (0x280f2000)
libiconv.so.3 => /usr/local/lib/libiconv.so.3 (0x28110000)
libapr-1.so.2 => /usr/local/lib/libapr-1.so.2 (0x281fd000)
libcrypt.so.3 => /lib32//libcrypt.so.3 (0x2821d000)
libpthread.so.2 => not found (0x0)
libc.so.6 => /lib32//libc.so.6 (0x28235000)
libpthread.so.2 => /usr/lib32/libpthread.so.2 (0x2830d000)
So it is possible, it just doesn't have the right options.
>How-To-Repeat:
>Fix:
The following patch will teach ldd(1) to handle them properly:
[/] root at ed-exigent>/tmp/ldd /usr/local/lib/libexpat.so /usr/lib/libssh.so /bin/sh /usr/local/bin/bash
/usr/local/lib/libexpat.so:
ldd: /usr/local/lib/libexpat.so: /usr/local/lib/libexpat.so: unsupported file layout
/usr/local/lib/libexpat.so: exit status 1
/usr/lib/libssh.so:
libz.so.3 => /lib/libz.so.3 (0x800963000)
libgssapi.so.8 => /usr/lib/libgssapi.so.8 (0x800a76000)
libkrb5.so.8 => /usr/lib/libkrb5.so.8 (0x800b85000)
libasn1.so.8 => /usr/lib/libasn1.so.8 (0x800cc9000)
libcom_err.so.3 => /usr/lib/libcom_err.so.3 (0x800df2000)
libmd.so.3 => /lib/libmd.so.3 (0x800ef4000)
libroken.so.8 => /usr/lib/libroken.so.8 (0x801000000)
libcrypto.so.4 => /lib/libcrypto.so.4 (0x80110e000)
libcrypt.so.3 => /lib/libcrypt.so.3 (0x801354000)
/bin/sh:
libedit.so.5 => /lib/libedit.so.5 (0x800646000)
libncurses.so.6 => /lib/libncurses.so.6 (0x800760000)
libc.so.6 => /lib/libc.so.6 (0x8008b9000)
/usr/local/bin/bash:
libncurses.so.6 => /lib32//libncurses.so.6 (0x28106000)
libintl.so.6 => /usr/local/lib/libintl.so.6 (0x28145000)
libiconv.so.3 => /usr/local/lib/libiconv.so.3 (0x2814e000)
libc.so.6 => /lib32//libc.so.6 (0x2823b000)
It can't do 32 bit libraries because dlopen() can't do it.
Index: ldd.1
===================================================================
--- ldd.1 (revision 179947)
+++ ldd.1 (working copy)
@@ -64,6 +64,11 @@
It will print a report of all ELF binaries in the current directory,
which link against libc.so.6:
.Dl "find . -type f | xargs -n1 file -F " " | grep ELF | cut -f1 -d' ' | xargs ldd -f '%A %o\en' | grep libc.so.6"
+.Sh BUGS
+On 64 bit architectures, dlopen() can't open 32 bit dynamica libraries
+and
+.Nm
+will show the error "unsupported file layout".
.Sh SEE ALSO
.Xr ld 1 ,
.Xr nm 1 ,
Index: ldd.c
===================================================================
--- ldd.c (revision 179947)
+++ ldd.c (working copy)
@@ -47,6 +47,45 @@
#include "extern.h"
+int is_executable(char *file, int *is_shlib, int *type);
+
+#define TYPE_AOUT 1
+#define TYPE_ELF32 2
+#define TYPE_ELF64 3
+
+#define ENV_OBJECTS 0
+#define ENV_OBJECTS_FMT1 1
+#define ENV_OBJECTS_FMT2 2
+#define ENV_OBJECTS_PROGNAME 3
+#define ENV_OBJECTS_ALL 4
+#define ENV_LAST 5
+
+#ifdef __i386__
+const char *env32[ENV_LAST] = {
+ "LD_TRACE_LOADED_OBJECTS",
+ "LD_TRACE_LOADED_OBJECTS_FMT1",
+ "LD_TRACE_LOADED_OBJECTS_FMT2",
+ "LD_TRACE_LOADED_OBJECTS_PROGNAME",
+ "LD_TRACE_LOADED_OBJECTS_ALL",
+};
+const char *env64[ENV_LAST] = {};
+#else
+const char *env64[ENV_LAST] = {
+ "LD_TRACE_LOADED_OBJECTS",
+ "LD_TRACE_LOADED_OBJECTS_FMT1",
+ "LD_TRACE_LOADED_OBJECTS_FMT2",
+ "LD_TRACE_LOADED_OBJECTS_PROGNAME",
+ "LD_TRACE_LOADED_OBJECTS_ALL",
+};
+const char *env32[ENV_LAST] = {
+ "LD_32_TRACE_LOADED_OBJECTS",
+ "LD_32_TRACE_LOADED_OBJECTS_FMT1",
+ "LD_32_TRACE_LOADED_OBJECTS_FMT2",
+ "LD_32_TRACE_LOADED_OBJECTS_PROGNAME",
+ "LD_32_TRACE_LOADED_OBJECTS_ALL",
+};
+#endif
+
static void
usage(void)
{
@@ -61,10 +100,11 @@
int rval;
int c;
int aflag, vflag;
+ const char **env;
aflag = vflag = 0;
- while ((c = getopt(argc, argv, "avf:")) != -1) {
+ while ((c = getopt(argc, argv, "23avf:")) != -1) {
switch (c) {
case 'a':
aflag++;
@@ -104,97 +144,38 @@
}
#endif
- /* ld.so magic */
- setenv("LD_TRACE_LOADED_OBJECTS", "yes", 1);
- if (fmt1)
- setenv("LD_TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);
- if (fmt2)
- setenv("LD_TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);
-
rval = 0;
for ( ; argc > 0; argc--, argv++) {
- int fd;
- union {
- struct exec aout;
- Elf_Ehdr elf;
- } hdr;
- int n;
int status;
- int file_ok;
int is_shlib;
+ int type;
- if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
- warn("%s", *argv);
+ if (is_executable(*argv, &is_shlib, &type) == 0) {
rval |= 1;
continue;
}
- if ((n = read(fd, &hdr, sizeof hdr)) == -1) {
- warn("%s: can't read program header", *argv);
- (void)close(fd);
- rval |= 1;
- continue;
+
+ switch (type) {
+ default:
+ case TYPE_AOUT: /* XXX */
+ case TYPE_ELF32:
+ env = env32;
+ break;
+ case TYPE_ELF64:
+ env = env64;
+ break;
}
- file_ok = 1;
- is_shlib = 0;
- if ((size_t)n >= sizeof hdr.aout && !N_BADMAG(hdr.aout)) {
- /* a.out file */
- if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
-#if 1 /* Compatibility */
- || hdr.aout.a_entry < __LDPGSZ
-#endif
- ) {
- warnx("%s: not a dynamic executable", *argv);
- file_ok = 0;
- }
- } else if ((size_t)n >= sizeof hdr.elf && IS_ELF(hdr.elf)) {
- Elf_Ehdr ehdr;
- Elf_Phdr phdr;
- int dynamic = 0, i;
+ /* ld.so magic */
+ setenv(env[ENV_OBJECTS], "yes", 1);
+ if (fmt1)
+ setenv(env[ENV_OBJECTS_FMT1], fmt1, 1);
+ if (fmt2)
+ setenv(env[ENV_OBJECTS_FMT2], fmt2, 1);
- if (lseek(fd, 0, SEEK_SET) == -1 ||
- read(fd, &ehdr, sizeof ehdr) != sizeof ehdr ||
- lseek(fd, ehdr.e_phoff, SEEK_SET) == -1
- ) {
- warnx("%s: can't read program header", *argv);
- file_ok = 0;
- } else {
- for (i = 0; i < ehdr.e_phnum; i++) {
- if (read(fd, &phdr, ehdr.e_phentsize)
- != sizeof phdr) {
- warnx("%s: can't read program header",
- *argv);
- file_ok = 0;
- break;
- }
- if (phdr.p_type == PT_DYNAMIC)
- dynamic = 1;
- }
- }
- if (!dynamic) {
- warnx("%s: not a dynamic executable", *argv);
- file_ok = 0;
- } else if (hdr.elf.e_type == ET_DYN) {
- if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) {
- is_shlib = 1;
- } else {
- warnx("%s: not a FreeBSD ELF shared "
- "object", *argv);
- file_ok = 0;
- }
- }
- } else {
- warnx("%s: not a dynamic executable", *argv);
- file_ok = 0;
- }
- (void)close(fd);
- if (!file_ok) {
- rval |= 1;
- continue;
- }
-
- setenv("LD_TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1);
- if (aflag) setenv("LD_TRACE_LOADED_OBJECTS_ALL", "1", 1);
+ setenv(env[ENV_OBJECTS_PROGNAME], *argv, 1);
+ if (aflag)
+ setenv(env[ENV_OBJECTS_ALL], "1", 1);
else if (fmt1 == NULL && fmt2 == NULL)
/* Default formats */
printf("%s:\n", *argv);
@@ -233,3 +214,149 @@
return rval;
}
+
+int
+is_executable(char *file, int *is_shlib, int *type)
+{
+ int fd;
+ union {
+ struct exec aout;
+ Elf_Ehdr elf;
+ } hdr;
+ int n;
+ int file_ok = 0;
+
+ if ((fd = open(file, O_RDONLY, 0)) < 0) {
+ warn("%s", file);
+ return (0);
+ }
+ if ((n = read(fd, &hdr, sizeof hdr)) == -1) {
+ warn("%s: can't read program header", file);
+ goto bye;
+ }
+
+ *is_shlib = 0;
+ if ((size_t)n >= sizeof hdr.aout && !N_BADMAG(hdr.aout)) {
+ /* a.out file */
+ if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
+#if 1 /* Compatibility */
+ || hdr.aout.a_entry < __LDPGSZ
+#endif
+ ) {
+ warnx("%s: not a dynamic a.out executable",
+ file);
+ goto bye;
+ }
+ file_ok = 1;
+ *type = TYPE_AOUT;
+ goto bye;
+ }
+
+ if ((size_t)n >= sizeof hdr.elf && IS_ELF(hdr.elf)) {
+
+ /* 32 bit object */
+ if (hdr.elf.e_ident[EI_CLASS] == 1) {
+ Elf32_Ehdr ehdr;
+ Elf32_Phdr phdr;
+ int dynamic = 0, i;
+
+ if (lseek(fd, 0, SEEK_SET) == -1 ||
+ read(fd, &ehdr, sizeof ehdr) != sizeof ehdr ||
+ lseek(fd, ehdr.e_phoff, SEEK_SET) == -1
+ ) {
+ warnx("%s: can't read program header", file);
+ goto bye;
+ }
+
+ for (i = 0; i < ehdr.e_phnum; i++) {
+ if (read(fd, &phdr, ehdr.e_phentsize)
+ != sizeof phdr) {
+ warnx("%s: can't read program header",
+ file);
+ goto bye;
+ }
+ if (phdr.p_type == PT_DYNAMIC)
+ dynamic = 1;
+ }
+
+ if (!dynamic) {
+ warnx("%s: not a dynamic ELF executable",
+ file);
+ goto bye;
+ }
+
+ if (ehdr.e_type == ET_DYN) {
+ if (ehdr.e_ident[EI_OSABI] &
+ ELFOSABI_FREEBSD) {
+ *is_shlib = 1;
+ file_ok = 1;
+ goto bye;
+ }
+ warnx("%s: not a FreeBSD ELF shared object",
+ file);
+ goto bye;
+ }
+
+ *type = TYPE_ELF32;
+ file_ok = 1;
+ goto bye;
+ }
+
+#ifndef __i386__
+ /* 64 bit object */
+ if (hdr.elf.e_ident[EI_CLASS] == 2) {
+ Elf64_Ehdr ehdr;
+ Elf64_Phdr phdr;
+ int dynamic = 0, i;
+
+ if (lseek(fd, 0, SEEK_SET) == -1 ||
+ read(fd, &ehdr, sizeof ehdr) != sizeof ehdr ||
+ lseek(fd, ehdr.e_phoff, SEEK_SET) == -1
+ ) {
+ warnx("%s: can't read program header", file);
+ goto bye;
+ }
+
+ for (i = 0; i < ehdr.e_phnum; i++) {
+ if (read(fd, &phdr, ehdr.e_phentsize)
+ != sizeof phdr) {
+ warnx("%s: can't read program header",
+ file);
+ goto bye;
+ }
+ if (phdr.p_type == PT_DYNAMIC)
+ dynamic = 1;
+ }
+
+ if (!dynamic) {
+ warnx("%s: not a dynamic ELF executable",
+ file);
+ goto bye;
+ }
+
+ if (ehdr.e_type == ET_DYN) {
+ if (ehdr.e_ident[EI_OSABI] &
+ ELFOSABI_FREEBSD) {
+ *is_shlib = 1;
+ file_ok = 1;
+ goto bye;
+ }
+ warnx("%s: not a FreeBSD ELF shared object",
+ file);
+ goto bye;
+ }
+
+ *type = TYPE_ELF64;
+ file_ok = 1;
+ goto bye;
+ }
+#endif
+ }
+
+ warnx("%s: not a known dynamic executable", file);
+ goto bye;
+
+bye:
+ (void)close(fd);
+ return (file_ok);
+}
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list