What are "unused DT entry" errors?
If you have reached this page, it's probably because you have
compiled or attempted to run some binaries on your ARM based Android
system, with the result that your binary/app crashes or generates a
lot of warnings in your logcat
. Typically something like this:
WARNING: linker: /blahblah/libopenssl.so: unused DT entry: type 0x6ffffffe arg 0x1188
Q: What is a "DT entry"?
In a few words, they are descriptive array entries in the file
structure of an ELF file. Specifically they are known as
Dynamic Array Tags
and are requirements for executable and
shared objects. However, not all entries are required or available,
depending on the processor and kernel architecture.
In our case we are faced with a "Warning" that one of these are "unused".
What that means is, that your executable or library (*.so
) files has been
compiled with the DT entry indicated, but your kernel is not supporting
that entry, for various reasons. The best examples are found on ARM based
Android systems, where the system library paths are fixed and the
cross compilers used for your firmware (OS/kernel) are set not to use
these entries. Usually the binaries still run just fine, but the kernel
is flagging this warning every time you're using it.
Q: When does this happen?
This can happen when:
- Your ARM kernel is cross-compiled using the wrong flags (usually meant for other processor architectures).
- Your ARM binaries and libraries are cross-compiled using AOS deprecated compilation flags.
- and probably other ways yet to be discovered..
Starting from 5.1 (API 22) the Android linker warns about the VERNEED and
VERNEEDNUM ELF dynamic sections.
The most common flags that cause this error on Android devices are:
DT_RPATH 0x0f (15) The DT_STRTAB string table offset of a null-terminated library search path string.
This element's use has been superseded by DT_RUNPATH.
DT_RUNPATH 0x1d (29) The DT_STRTAB string table offset of a null-terminated library search path string.
DT_VERNEED 0x6ffffffe The address of the version dependency table. Elements within this table contain
indexes into the string table DT_STRTAB. This element requires that the
DT_VERNEEDNUM element also be present.
DT_VERNEEDNUM 0x6fffffff The number of entries in the DT_VERNEEDNUM table.
Tracking down the error above, we find that this message comes from the bionic
library linker.cpp:
case DT_VERNEED:
verneed_ptr_ = load_bias + d->d_un.d_ptr;
break;
case DT_VERNEEDNUM:
verneed_cnt_ = d->d_un.d_val;
break;
case DT_RUNPATH:
// this is parsed after we have strtab initialized (see below).
break;
default:
if (!relocating_linker) {
DL_WARN(""%s" unused DT entry: type %p arg %p", get_realpath(),
reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
}
break;
}
The code (above) supporting this symbol versioning was committed on April 9, 2015. Thus if your NDK build is either set to support API's earlier than this, or using build tools linking to this earlier library, you will get these warnings.
Q: How do I find what DT entries my system or binaries are using?
There are many ways to do this:
- You look into your kernel sources for
<linux/elf.h>
.
- You look in your Android NDK installation folders and check:
# To find all elf.h files:
find /<path_to>/ndk/platforms/android-*/arch-arm*/usr/include/linux/ -iname "elf.h"
- Do an
readelf
of your binary:
$ readelf --dynamic libopenssl.so
Dynamic section at offset 0x23b960 contains 28 entries:
Tag Type Name/Value
0x00000003 (PLTGOT) 0x23ce18
0x00000002 (PLTRELSZ) 952 (bytes)
0x00000017 (JMPREL) 0x15e70
0x00000014 (PLTREL) REL
0x00000011 (REL) 0x11c8
0x00000012 (RELSZ) 85160 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x6ffffffa (RELCOUNT) 10632
0x00000015 (DEBUG) 0x0
0x00000006 (SYMTAB) 0x148
0x0000000b (SYMENT) 16 (bytes)
0x00000005 (STRTAB) 0x918
0x0000000a (STRSZ) 1011 (bytes)
0x00000004 (HASH) 0xd0c
0x00000001 (NEEDED) Shared library: [libdl.so]
0x00000001 (NEEDED) Shared library: [libc.so]
0x0000001a (FINI_ARRAY) 0x238458
0x0000001c (FINI_ARRAYSZ) 8 (bytes)
0x00000019 (INIT_ARRAY) 0x238460
0x0000001b (INIT_ARRAYSZ) 16 (bytes)
0x00000020 (PREINIT_ARRAY) 0x238470
0x00000021 (PREINIT_ARRAYSZ) 0x8
0x0000001e (FLAGS) BIND_NOW
0x6ffffffb (FLAGS_1) Flags: NOW
0x6ffffff0 (VERSYM) 0x108c
0x6ffffffe (VERNEED) 0x1188
0x6fffffff (VERNEEDNUM) 2
0x00000000 (NULL) 0x0
As you can see from the error above, the type
corresponds to DT_VERNEED
.
From THIS document:
DT_RPATH
This element holds the string table offset of a null-terminated search
library search path string, discussed in "Shared Object Dependencies."
The offset is an index into the table recorded in the DT_STRTAB entry.
DT_RPATH may give a string that holds a list of directories, separated
by colons (:). All LD_LIBRARY_PATH directories are searched after
those from DT_RPATH.
Q: So how do you solve or deal with these issues?
There are essentially 3 ways to deal with this:
- the quick
- the bad
- the ugly
The Quick (you don't have any sources or just can't be bothered)
Use an "ELF cleaner" to remove the offending DT entries from a all your binaries. This is an easy and quick remedy, especially when you don't have the sources to recompile them properly for your system. There are at least two cleaners out there that you can use.
The Bad (you have the sources)
Is the right way to do it, because you'll become a bad-ass ARM cross compiler guru in the process of getting it to work. You basically need to find and tune the compiler settings in the Makefiles used.
From here:
The Android linker (/system/bin/linker) does not support RPATH or RUNPATH, so we set LD_LIBRARY_PATH=$USR/lib and try to avoid building useless rpath entries with --disable-rpath configure flags. Another option to avoid depending on LD_LIBRARY_PATH would be supplying a custom linker - this is not done due to the overhead of maintaining a custom linker.
The Ugly (You just want your app to work with any dirty binary.)
You tell your Java app not to freak out when checking for null
in error handlers and instead get fed these warnings, possibly
causing fatal exceptions. Use something like:
class OpensslErrorThread extends Thread {
@Override
public void run() {
try {
while(true){
String line = opensslStderr.readLine();
if(line == null){
// OK
return;
}
if(line.contains("unused DT entry")){
Log.i(TAG, "Ignoring "unused DT entry" error from openssl: " + line);
} else {
// throw exception!
break;
}
}
} catch(Exception e) {
Log.e(TAG, "Exception!")
}
}
}
This is very bad and ugly as it doesn't solve anything, while bloating your code. In addition, the warnings are there for a reason, and that is that in future AOS versions, this will become a full fledged error!
Q. What else?
Many changes in the API's between 18-25 (J to N) has been made in
way the Android kernel and libraries are compiled. I cannot
provide a remotely close explanation of all that, but perhaps this
will help guide you in the right direction. The best sources is
of course looking in the Android sources and documentation itself.
For example, HERE or HERE.
And finally the full list:
Name Value d_un Executable Shared Object
---------------------------------------------------------------------------------------------
DT_NULL 0 Ignored Mandatory Mandatory
DT_NEEDED 1 d_val Optional Optional
DT_PLTRELSZ 2 d_val Optional Optional
DT_PLTGOT 3 d_ptr Optional Optional
DT_HASH 4 d_ptr Mandatory Mandatory
DT_STRTAB 5 d_ptr Mandatory Mandatory
DT_SYMTAB 6 d_ptr Mandatory Mandatory
DT_RELA 7 d_ptr Mandatory Optional
DT_RELASZ 8 d_val Mandatory Optional
DT_RELAENT 9 d_val Mandatory Optional
DT_STRSZ 0x0a (10) d_val Mandatory Mandatory
DT_SYMENT 0x0b (11) d_val Mandatory Mandatory
DT_INIT 0x0c (12) d_ptr Optional Optional
DT_FINI 0x0d (13) d_ptr Optional Optional
DT_SONAME