Android二进制工具objdump/readelf不能打印出function@plt的原因和补丁. 查找原因时, google到的一点资料.
有人解决了后, Google的工程师也火急火燎地让上传补丁. :)
objdump not printing "function@plt" symbols when processing arm or mips object, but does for x86.
As one would expect of a modern toolchain targeting a shared library system, the ndk toolchain creates executables in which calls to external library functions are implemented with a call to a helper in the .plt section, which redirects to the address in the global offset table where the runtime linker will eventually place the address of the target function.
If I compile a simple hello-world executable with the ndk targeting both x86 and arm, then objdump the x86 version, I get something like this (trimmed a lot for brevity):
$ i686-android-linux-objdump -d obj/local/x86/hello
Disassembly of section .plt:
0804827c <puts@plt>:
804827c: ff 25 58 95 04 08 jmp *0x8049558
8048282: 68 00 00 00 00 push $0x0
8048287: e9 e0 ff ff ff jmp 804826c <puts@plt-0x10>
Disassembly of section .text:
080483c0 <main>:
80483de: e8 99 fe ff ff call 804827c <puts@plt>
But, for the arm version:
$arm-linux-androideabi-objdump -d obj/local/armeabi/hello
Disassembly of section .plt:
000084f8 <.plt>:
8524: e28fc600 add ip, pc, #0 ; 0x0
8528: e28cca02 add ip, ip, #8192 ; 0x2000
852c: e5bcf7a4 ldr pc, [ip, #1956]!
0008590 <main>:
8590: b510 push {r4, lr}
8592: 4803 ldr r0, [pc, #12] (85a0 <main+0x10>)
8594: 4478 add r0, pc
8596: f7ff efc6 blx 8524 <_start-0x3c>
As you can see, there is no "puts@plt" synthetic symbol created, and the invocation within the program code is left as a negative address in relation to the first known symbol. Needless to say, this makes making sense of dumps very complicated - extremely so if looking at a stripped executable where the dynamic link symbols of the library functions used may be the only major clues as to what you are looking at.
So I would like to figure out why this useful feature of displaying the names of library functions called via the plt works for x86, and not for arm. I know that the necessary information to create these synthetic symbols does exist in the file, because I wrote a program which pattern matches the opcodes of the .plt, figures out the target address then searches for a dynamic symbol and at that address and prints out the corresponding stringtab name with a section suffix in
the way I assme objdump/BFD is doing for x86:
$ printplt obj/local/armeabi/hello
decoding plt...
0x0000850c: __cxa_begin_cleanup@plt
0x00008518: memcpy@plt
0x00008524: puts@plt
0x00008530: abort@plt
0x0000853c: __libc_init@plt
0x00008548: __cxa_type_match@plt
0x00008554: __gnu_Unwind_Find_exidx@plt
So my question is, why is this not working with the arm objdump? (it does not seem to work for mips either)
- Is there metadata missing from the arm object which is key to objdump / BFD deciding to try to do this?
- Is the feature just not implemented for arm?
- Is it implemented, but not available in the prebuilt toolchain due to omission of a compile-time option?
- Is it failing because the instructions used in the .plt are not of the form expected?
Unfortunately, I have not yet been able to figure out where these synthetic symbols are created in the binutils source; there's not a lot to search on since the "@plt" is presumably named from the section rather than being a static string, so it seems finding the code would require developing a degree of understanding of the codebase.
If possible, I'd like to find the area where binutils could be patched to enable this for arm, as it's a capability I would really like to have when debugging projects (and poking around on the device in general). If I can't figure out how to put it into objdump, I guess I could clean up and share my plt parsing program, but it would be a lot nicer to have the names in the disassembled output (and putting them in after the fact with sed seems a bit roundabout).
Managed to solve my problem - objdump now displays the function@pltnames is the disassembly of both the .plt and program code which calls them.
Patch follows... I suppose it's time to figure out how to use gerrit.
Which version of binutils would it be appropriate to submit against? I tried this on 2.21 but see there are lots in the git package. Or should it go upstream to someone else and only then back into android?
--- bfd/elf32-arm-orig.c 2012-06-27 16:12:27.000000000 -0400
+++ bfd/elf32-arm.c 2012-06-27 16:31:05.000000000 -0400
@@ -13898,6 +13898,21 @@
#define elf_backend_obj_attrs_order elf32_arm_obj_attrs_order
#define elf_backend_obj_attrs_handle_unknown
elf32_arm_obj_attrs_handle_unknown
+/* Changes to enable decoding of function@plt symbols for android */
+#undef elf_backend_plt_sym_val
+#define elf_backend_plt_sym_val elf32_arm_android_plt_sym_val
+
+/* Return address for Ith PLT stub in section PLT, for relocation REL
+ or (bfd_vma) -1 if it should not be included. */
+
+static bfd_vma
+elf32_arm_android_plt_sym_val (bfd_vma i, const asection *plt,
+ const arelent *rel ATTRIBUTE_UNUSED)
+{
+ return plt->vma + 4 * (
+ ARRAY_SIZE(elf32_arm_plt0_entry) +
+ ARRAY_SIZE(elf32_arm_plt_entry) * i);
+}
#include "elf32-target.h"
/* VxWorks Targets. */
Thank you for figuring out the fix! Please submit it to AOSP toolchain repo
repo init -u https://android.googlesource.com/toolchain/manifest.git
repo sync
You may google for how to submit patch to AOSP, but in short.
cd binutils
repo start yourbranchname .
Apply changes to binutils/binutils-2.19 and ideally also in binutils/binutils-2.21
git commit -a # write commit message
repo upload . # then add reviewer
Your upload will appear in https://android-review.googlesource.com for review.
Looking forward to see it soon.