Es gibt Zeiten, in denen Sie eine Objektdatei, die für eine Art von Plattform (wie ARM oder x86) verfügbar ist, auf eine andere Art von Plattform portieren müssen. Wenn der Quellcode verfügbar ist, ist es relativ einfach, da er auf der Zielplattform neu kompiliert werden kann. Was aber, wenn der Quellcode nicht verfügbar ist und Sie dennoch eine Objektdatei von einem Plattformtyp auf einen anderen portieren müssen? Nun, wenn Sie Linux verwenden, dann macht der Befehl objcopy genau das Erforderliche. In diesem Artikel lernen wir die grundlegende Verwendung dieses Befehls anhand einiger Beispiele kennen.
Da ich nur auf x86_64-Plattformen arbeite, werde ich versuchen, einige plattformneutrale Funktionen dieses Befehls in diesem Tutorial zu behandeln.
Die Syntax dieses Befehls lautet:
objcopy [options] infile [outfile]...
Beachten Sie, dass die „Optionen“ und „Ausgabedatei“ keine obligatorischen Argumente sind, sondern ihre eigene Bedeutung haben.
Beispiele
1. Kopieren Sie einfach die Objektdatei von der Quelle zum Ziel
Betrachten Sie das folgende Beispiel:
$ objcopy test new_test $
Der obige Befehl kopiert also „test“ in eine neue Datei „new_test“. Beachten Sie, dass „test“ in diesem Fall auf derselben Plattform kompiliert wurde, sodass sich die Ausgabe „new_test“ nicht unterscheidet.
Wenn Sie eine Binärdatei disassemblieren und mehr Details zu Ihren Objektdateien erhalten möchten, sollten Sie den objdump-Befehl verwenden, wie wir zuvor erklärt haben.
2. Kopieren Sie die Objektdatei, ohne den neuen Dateinamen anzugeben
Im obigen Beispiel wurde die kopierte Datei „new_test“ genannt, da sie zusammen mit Optionen für den Befehl bereitgestellt wurde. Wenn jedoch kein Zieldateiname angegeben wird, ersetzt der objcopy-Befehl die Originaldatei durch die kopierte Datei.
Betrachten Sie das folgende Beispiel:
$ stat test File: `test' Size: 8498 Blocks: 24 IO Block: 4096 regular file Device: 805h/2053d Inode: 1442357 Links: 1 Access: (0755/-rwxr-xr-x) Uid: ( 1000/himanshu) Gid: ( 1001/ family) Access: 2012-08-31 21:25:54.828808055 +0530 Modify: 2012-08-31 21:25:50.498614487 +0530 Change: 2012-08-31 21:25:50.498614487 +0530 $ objcopy test $ stat test File: `test' Size: 8498 Blocks: 24 IO Block: 4096 regular file Device: 805h/2053d Inode: 1459714 Links: 1 Access: (0755/-rwxr-xr-x) Uid: ( 1000/himanshu) Gid: ( 1001/ family) Access: 2012-08-31 21:30:04.108833244 +0530 Modify: 2012-08-31 21:30:04.108833244 +0530 Change: 2012-08-31 21:30:04.108833244 +0530
Wir sehen also, dass die Statistik der Objektdatei „test“ komplett geändert wurde, da objcopy sie als komplett neue Datei erstellt hat.
3. Kopieren Sie nur einen bestimmten Abschnitt mit der Option -j
Wenn Sie nur einen Abschnitt von der Quellobjektdatei in die Zielobjektdatei kopieren möchten, wird in diesem Fall die Option -j verwendet.
Betrachten Sie das folgende Beispiel:
$ objcopy -j.interp test new_test $
Der obige Befehl kopiert tatsächlich nur den .interp-Abschnitt in die leere new_test-Datei.
Wenn wir es bestätigen:
$ objdump -s new_test new_test: file format elf64-x86-64 Contents of section .interp: 400238 2f6c6962 36342f6c 642d6c69 6e75782d /lib64/ld-linux- 400248 7838362d 36342e73 6f2e3200 x86-64.so.2.
Wir sehen also, dass diese Datei nur den .interp-Abschnitt enthält (den wir von ‚test‘ kopiert haben).
4. Entfernen Sie nur einen bestimmten Abschnitt aus der kopierten Datei mit der Option -R
Diese Option lässt den objdump-Befehl die komplette Quelldatei außer den Abschnitten kopieren, die zusammen mit dieser Option angegeben werden.
Betrachten Sie das folgende Beispiel:
$ objcopy -R.interp test new_test
Wenn wir bestätigen:
$ objdump -s -j.interp new_test new_test: file format elf64-x86-64
Wir sehen also, dass sich in der neuen Datei „new_test“ kein .interp-Abschnitt befindet.
5. Bewahren Sie die Zugriffs- und Änderungsdaten mit der Option -p auf
Die Zugriffs- und Änderungsdaten der kopierten Datei können beibehalten werden (können gleich wie die Quelle bleiben), indem Sie die Option -p zusammen mit diesem Befehl verwenden.
Betrachten Sie das folgende Beispiel:
$ objcopy -p test new_tst
Der obige Befehl behält das Zugriffs- und Änderungsdatum/-zeit bei.
Wenn wir bestätigen:
$ $ stat test File: `test' Size: 8498 Blocks: 24 IO Block: 4096 regular file Device: 805h/2053d Inode: 1459714 Links: 1 Access: (0755/-rwxr-xr-x) Uid: ( 1000/himanshu) Gid: ( 1001/ family) Access: 2012-08-31 21:32:32.458629723 +0530 Modify: 2012-08-31 21:30:04.108833244 +0530 Change: 2012-08-31 21:30:04.108833244 +0530 $ stat new_tst File: `new_tst' Size: 8498 Blocks: 24 IO Block: 4096 regular file Device: 805h/2053d Inode: 1442650 Links: 1 Access: (0755/-rwxr-xr-x) Uid: ( 1000/himanshu) Gid: ( 1001/ family) Access: 2012-08-31 21:32:32.000000000 +0530 Modify: 2012-08-31 21:30:04.000000000 +0530 Change: 2012-08-31 21:42:25.938657423 +0530
Wir sehen also, dass sowohl Zugriffs- als auch Änderungszeit/-datum beibehalten wurden.
6. Ändern Sie alle globalen Symbole mit der Option –weaken
auf schwachDies kann beim Erstellen einer Objektdatei nützlich sein, die mit anderen Objektdateien verknüpft werden kann, indem die Option -R für den Linker verwendet wird.
Betrachten Sie das folgende Beispiel:
$ readelf -s new_test Symbol table '.dynsym' contains 4 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2) 2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) Symbol table '.symtab' contains 65 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000400238 0 SECTION LOCAL DEFAULT 1 2: 0000000000400254 0 SECTION LOCAL DEFAULT 2 3: 0000000000400274 0 SECTION LOCAL DEFAULT 3 4: 0000000000400298 0 SECTION LOCAL DEFAULT 4 .. 27: 0000000000000000 0 SECTION LOCAL DEFAULT 27 28: 000000000040046c 0 FUNC LOCAL DEFAULT 14 call_gmon_start 29: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c .. 49: 0000000000400550 2 FUNC GLOBAL DEFAULT 14 __libc_csu_fini 50: 0000000000400440 0 FUNC GLOBAL DEFAULT 14 _start 51: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 52: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 53: 0000000000400628 0 FUNC GLOBAL DEFAULT 15 _fini 54: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_ 55: 0000000000400638 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used .. $ objcopy --weaken test new_test $ readelf -s new_test Symbol table '.dynsym' contains 4 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2) 2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) Symbol table '.symtab' contains 65 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000400238 0 SECTION LOCAL DEFAULT 1 2: 0000000000400254 0 SECTION LOCAL DEFAULT 2 3: 0000000000400274 0 SECTION LOCAL DEFAULT 3 4: 0000000000400298 0 SECTION LOCAL DEFAULT 4 .. 28: 000000000040046c 0 FUNC LOCAL DEFAULT 14 call_gmon_start 29: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 30: 0000000000600e18 0 OBJECT LOCAL DEFAULT 19 __CTOR_LIST__ 31: 0000000000600e28 0 OBJECT LOCAL DEFAULT 20 __DTOR_LIST__ 32: 0000000000600e38 0 OBJECT LOCAL DEFAULT 21 __JCR_LIST__ ... 49: 0000000000400550 2 FUNC WEAK DEFAULT 14 __libc_csu_fini 50: 0000000000400440 0 FUNC WEAK DEFAULT 14 _start 51: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 52: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 53: 0000000000400628 0 FUNC WEAK DEFAULT 15 _fini 54: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_ 55: 0000000000400638 4 OBJECT WEAK DEFAULT 16 _IO_stdin_used 56: 0000000000601010 0 NOTYPE WEAK DEFAULT 25 __data_start .. $
Wir sehen also, dass nach dem Ausführen des Befehls objcopy mit dem Flag –weaken alle GLOBAL-Symbole in WEAK konvertiert wurden.
7. Stellen Sie Symbole mit einer Zeichenfolge voran, indem Sie die Option –prefix-symbols
verwendenBetrachten Sie das folgende Beispiel, in dem eine Zeichenfolge „TGS“ vor Symbolnamen vorangestellt werden soll:
$ objcopy --prefix-symbols="TGS" test new_test $ readelf -s new_test Symbol table '.dynsym' contains 4 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2) 2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) Symbol table '.symtab' contains 65 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000400238 0 SECTION LOCAL DEFAULT 1 2: 0000000000400254 0 SECTION LOCAL DEFAULT 2 3: 0000000000400274 0 SECTION LOCAL DEFAULT 3 4: 0000000000400298 0 SECTION LOCAL DEFAULT 4 ... 28: 000000000040046c 0 FUNC LOCAL DEFAULT 14 TGScall_gmon_start 29: 0000000000000000 0 FILE LOCAL DEFAULT ABS TGScrtstuff.c 30: 0000000000600e18 0 OBJECT LOCAL DEFAULT 19 TGS__CTOR_LIST__ 31: 0000000000600e28 0 OBJECT LOCAL DEFAULT 20 TGS__DTOR_LIST__ 32: 0000000000600e38 0 OBJECT LOCAL DEFAULT 21 TGS__JCR_LIST__ 33: 0000000000400490 0 FUNC LOCAL DEFAULT 14 TGS__do_global_dtors_aux ...
Wir sehen also, dass „TGS“ vor Symbolnamen vorangestellt wurde.
8. Entfernen Sie ein bestimmtes Symbol mit der Option –strip-symbols
Falls einige Symbole entfernt werden müssen, kann die Option –strip-symbols zusammen mit einem Dateinamen verwendet werden. Dieser Dateiname enthält die zu entfernenden Symbolnamen (einer in jeder Zeile).
Betrachten Sie das folgende Beispiel, in dem der Symbolname „call_gmon_start“ entfernt wird, wie er in einer Datei angegeben ist (symbolname).
$ readelf -s new_test Symbol table '.dynsym' contains 4 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2) 2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) Symbol table '.symtab' contains 65 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000400238 0 SECTION LOCAL DEFAULT 1 2: 0000000000400254 0 SECTION LOCAL DEFAULT 2 3: 0000000000400274 0 SECTION LOCAL DEFAULT 3 4: 0000000000400298 0 SECTION LOCAL DEFAULT 4 ..... 28: 000000000040046c 0 FUNC LOCAL DEFAULT 14 call_gmon_start 29: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 30: 0000000000600e18 0 OBJECT LOCAL DEFAULT 19 __CTOR_LIST__ 31: 0000000000600e28 0 OBJECT LOCAL DEFAULT 20 __DTOR_LIST__ 32: 0000000000600e38 0 OBJECT LOCAL DEFAULT 21 __JCR_LIST__ 33: 0000000000400490 0 FUNC LOCAL DEFAULT 14 __do_global_dtors_aux ... $ objcopy --strip-symbols=symbolname test new_test $ readelf -s new_test Symbol table '.dynsym' contains 4 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2) 2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) Symbol table '.symtab' contains 64 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000400238 0 SECTION LOCAL DEFAULT 1 2: 0000000000400254 0 SECTION LOCAL DEFAULT 2 3: 0000000000400274 0 SECTION LOCAL DEFAULT 3 4: 0000000000400298 0 SECTION LOCAL DEFAULT 4 ... 26: 0000000000601020 0 SECTION LOCAL DEFAULT 26 27: 0000000000000000 0 SECTION LOCAL DEFAULT 27 28: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 29: 0000000000600e18 0 OBJECT LOCAL DEFAULT 19 __CTOR_LIST__ 30: 0000000000600e28 0 OBJECT LOCAL DEFAULT 20 __DTOR_LIST__ 31: 0000000000600e38 0 OBJECT LOCAL DEFAULT 21 __JCR_LIST__ 32: 0000000000400490 0 FUNC LOCAL DEFAULT 14 __do_global_dtors_aux ...
Wir sehen also, dass das Symbol „call_gmon_start“ erfolgreich entfernt wurde.
9. Stellen Sie den Abschnittsnamen eine Zeichenfolge voran, indem Sie die Option –prefix-sections
verwendenBetrachten Sie das folgende Beispiel:
$ objcopy --prefix-sections="TGS" test new_test $ readelf -s new_test readelf: Error: no .dynamic section in the dynamic segment Symbol table 'TGS.dynsym' contains 4 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND ... ... ...
Wir sehen also, dass dem Abschnittsnamen unsere bereitgestellte Zeichenfolge TGS.
vorangestellt wurde10. Behalten Sie das Symbol des Quelldateinamens mit der Option –keep-file-symbols
beiImmer wenn das –strip-debug-Symbol verwendet wird (das viele Debugging-bezogene Symbole zusammen mit dem Symbol, das den Dateinamen angibt), verwendet wird, wenn es notwendig ist, das Symbol für den Quelldateinamen beizubehalten, kann –keep-file-symbols verwendet werden.
Betrachten Sie das folgende Beispiel:
$ objcopy --strip-debug test new_test $ readelf -s new_test Symbol table '.dynsym' contains 4 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2) 2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) Symbol table '.symtab' contains 62 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 000000000040046c 0 FUNC LOCAL DEFAULT 14 call_gmon_start 2: 0000000000600e18 0 OBJECT LOCAL DEFAULT 19 __CTOR_LIST__ 3: 0000000000600e28 0 OBJECT LOCAL DEFAULT 20 __DTOR_LIST__ 4: 0000000000600e38 0 OBJECT LOCAL DEFAULT 21 __JCR_LIST__ ... 10: 00000000004006e8 0 OBJECT LOCAL DEFAULT 18 __FRAME_END__ 11: 0000000000600e38 0 OBJECT LOCAL DEFAULT 21 __JCR_END__ 12: 00000000004005f0 0 FUNC LOCAL DEFAULT 14 __do_global_ctors_aux 13: 0000000000600fe8 0 OBJECT LOCAL HIDDEN 24 _GLOBAL_OFFSET_TABLE_ 14: 0000000000600e14 0 NOTYPE LOCAL HIDDEN 19 __init_array_end 15: 0000000000600e14 0 NOTYPE LOCAL HIDDEN 19 __init_array_start ... $ objcopy --strip-debug --keep-file-symbols test new_test $ readelf -s new_test Symbol table '.dynsym' contains 4 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2) 2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) Symbol table '.symtab' contains 65 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 000000000040046c 0 FUNC LOCAL DEFAULT 14 call_gmon_start 2: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 3: 0000000000600e18 0 OBJECT LOCAL DEFAULT 19 __CTOR_LIST__ 4: 0000000000600e28 0 OBJECT LOCAL DEFAULT 20 __DTOR_LIST__ ... 12: 00000000004006e8 0 OBJECT LOCAL DEFAULT 18 __FRAME_END__ 13: 0000000000600e38 0 OBJECT LOCAL DEFAULT 21 __JCR_END__ 14: 00000000004005f0 0 FUNC LOCAL DEFAULT 14 __do_global_ctors_aux 15: 0000000000000000 0 FILE LOCAL DEFAULT ABS test.c 16: 0000000000600fe8 0 OBJECT LOCAL HIDDEN 24 _GLOBAL_OFFSET_TABLE_ 17: 0000000000600e14 0 NOTYPE LOCAL HIDDEN 19 __init_array_end 18: 0000000000600e14 0 NOTYPE LOCAL HIDDEN 19 __init_array_start ...
Im obigen Beispiel wurde zunächst objcopy mit der Option –strip-debug ausgeführt, die (zusammen mit vielen anderen Symbolen) das Symbol entfernte, das den Namen der Quelldatei (test.c) erwähnte. Als nächstes führen wir den Befehl objcopy zusammen mit der Option –keep-file-symbols erneut aus und stellen fest (in Fettschrift), dass das Symbol für den Quelldateinamen nicht entfernt wurde.