Il y a des moments où vous devez porter un fichier objet disponible pour un type de plate-forme (comme ARM ou x86) vers un autre type de plate-forme. Les choses sont relativement faciles si le code source est disponible car il peut être recompilé sur la plate-forme cible. Mais que se passe-t-il si le code source n'est pas disponible et que vous devez toujours porter un fichier objet d'un type de plate-forme à un autre ? Eh bien, si vous utilisez Linux, la commande objcopy fait exactement ce qui est requis. Dans cet article, nous allons apprendre l'utilisation de base de cette commande à travers quelques exemples.
Étant donné que je travaille uniquement sur le type de plate-forme x86_64, je vais donc essayer de couvrir certaines fonctionnalités neutres de la plate-forme de cette commande dans ce didacticiel.
La syntaxe de cette commande est :
objcopy [options] infile [outfile]...
Notez que les 'options' et 'outfile' ne sont pas des arguments obligatoires mais ont leur propre signification.
Exemples
1. Copiez simplement le fichier objet de la source à la destination
Prenons l'exemple suivant :
$ objcopy test new_test $
Ainsi, la commande ci-dessus copiera "test" dans un nouveau fichier "new_test". Notez que puisque dans ce cas, "test" a été compilé sur la même plate-forme, la sortie "new_test" ne sera donc pas différente.
De plus, si vous souhaitez désassembler un fichier binaire et obtenir plus de détails sur vos fichiers objets, vous devez utiliser la commande objdump comme nous l'avons expliqué précédemment.
2. Copiez le fichier objet sans fournir le nouveau nom de fichier
Dans l'exemple ci-dessus, le fichier copié a été nommé "new_test" car il a été fourni avec les options de la commande. Mais, si aucun nom de fichier de destination n'est fourni, la commande objcopy remplace le fichier d'origine par le fichier copié.
Prenons l'exemple suivant :
$ 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
Nous voyons donc que les statistiques du fichier objet "test" ont été complètement modifiées car objcopy l'a créé en tant que fichier complètement nouveau.
3. Copiez uniquement une section particulière à l'aide de l'option -j
Si vous souhaitez copier une seule section du fichier objet source vers le fichier objet de destination, l'option -j est utilisée dans ce cas.
Prenons l'exemple suivant :
$ objcopy -j.interp test new_test $
La commande ci-dessus copiera en fait uniquement la section .interp dans le fichier new_test vide.
Si nous le confirmons :
$ 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.
Nous voyons donc que ce fichier ne contient que la section .interp (que nous avons copiée de 'test' ).
4. Supprimer uniquement une section particulière du fichier copié à l'aide de l'option -R
Cette option permet à la commande objdump de copier le fichier source complet à l'exception des sections spécifiées avec cette option.
Prenons l'exemple suivant :
$ objcopy -R.interp test new_test
Si nous confirmons :
$ objdump -s -j.interp new_test new_test: file format elf64-x86-64
Nous voyons donc qu'aucune section .interp n'est dans le nouveau fichier 'new_test'.
5. Conserver les dates d'accès et de modification à l'aide de l'option -p
Les dates d'accès et de modification du fichier copié peuvent être conservées (peuvent être conservées comme la source) en utilisant l'option -p avec cette commande.
Prenons l'exemple suivant :
$ objcopy -p test new_tst
La commande ci-dessus conservera la date/heure d'accès et de modification.
Si nous confirmons :
$ $ 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
Nous voyons donc que l'heure/la date d'accès et de modification a été préservée.
6. Changez tous les symboles globaux en faible en utilisant l'option -weaken
Cela peut être utile lors de la création d'un fichier objet pouvant être lié à d'autres fichiers objets à l'aide de l'option -R de l'éditeur de liens.
Prenons l'exemple suivant :
$ 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 .. $
Nous voyons donc qu'après avoir exécuté la commande objcopy avec l'indicateur –weaken, tous les symboles GLOBAL ont été convertis en WEAK.
7. Préfixer les symboles avec une chaîne à l'aide de l'option –prefix-symbols
Considérez l'exemple suivant où une chaîne "TGS" doit être préfixée avant les noms de symboles :
$ 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 ...
Nous voyons donc que "TGS" était préfixé avant les noms de symboles.
8. Supprimez un symbole particulier à l'aide de l'option –strip-symbols
Dans le cas où certains symboles doivent être supprimés, l'option –strip-symbols peut être utilisée avec un nom de fichier. Ce nom de fichier contient les noms des symboles à supprimer (un dans chaque ligne).
Considérez l'exemple suivant où le nom du symbole "call_gmon_start" sera supprimé car il est spécifié dans un fichier (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 ...
Nous voyons donc que le symbole "call_gmon_start" a été supprimé avec succès.
9. Préfixez les noms de section avec une chaîne en utilisant l'option –prefix-sections
Prenons l'exemple suivant :
$ 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 ... ... ...
Nous voyons donc que le nom de la section était précédé de notre chaîne TGS fournie.
10. Conserver le symbole du nom du fichier source à l'aide de l'option –keep-file-symbols
Chaque fois que vous utilisez le symbole –strip-debug (qui supprime de nombreux symboles liés au débogage avec le symbole spécifiant le nom du fichier), s'il apparaît nécessaire de conserver le symbole du nom du fichier source, alors –keep-file-symbols peut être utilisé.
Prenons l'exemple suivant :
$ 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 ...
Dans l'exemple ci-dessus, objcopy a d'abord été exécuté avec l'option –strip-debug qui (avec de nombreux autres symboles) a supprimé le symbole mentionnant le nom du fichier source (test.c). Ensuite, nous avons réexécuté la commande objcopy avec l'option –keep-file-symbols et observé (en gras) que le symbole du nom du fichier source n'a pas été supprimé.