Hay momentos en los que necesita transferir un archivo de objeto disponible para un tipo de plataforma (como ARM o x86) a otro tipo de plataforma. Las cosas son relativamente fáciles si el código fuente está disponible, ya que se puede volver a compilar en la plataforma de destino. Pero, ¿qué sucede si el código fuente no está disponible y aún necesita transferir un archivo de objeto de un tipo de plataforma a otro? Bueno, si está utilizando Linux, el comando objcopy hace exactamente lo requerido. En este artículo, aprenderemos el uso básico de este comando a través de algunos ejemplos.
Dado que solo trabajo en el tipo de plataforma x86_64, intentaré cubrir algunas funciones neutrales de plataforma de este comando en este tutorial.
La sintaxis de este comando es:
objcopy [options] infile [outfile]...
Tenga en cuenta que las "opciones" y el "archivo de salida" no son argumentos obligatorios, pero tienen su propio significado.
Ejemplos
1. Simplemente copie el archivo de objeto del origen al destino
Considere el siguiente ejemplo:
$ objcopy test new_test $
Entonces, el comando anterior copiará 'prueba' en un nuevo archivo 'nueva_prueba'. Tenga en cuenta que, dado que en este caso, la "prueba" se compiló en la misma plataforma, por lo que la salida "nueva_prueba" no será diferente.
Además, si desea desensamblar un archivo binario y obtener más detalles sobre sus archivos de objetos, debe usar el comando objdump como explicamos anteriormente.
2. Copie el archivo de objeto sin proporcionar el nuevo nombre de archivo
En el ejemplo anterior, el archivo copiado se denominó "nueva_prueba", ya que se suministró junto con las opciones del comando. Pero, si no se proporciona un nombre de archivo de destino, el comando objcopy reemplaza el archivo original con el archivo copiado.
Considere el siguiente ejemplo:
$ 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
Entonces vemos que las estadísticas del archivo de objeto 'prueba' se cambiaron por completo ya que objcopy lo creó como un archivo completamente nuevo.
3. Copie solo una sección en particular usando la opción -j
Si desea copiar solo una sección del archivo de objeto de origen al archivo de objeto de destino, en este caso se utiliza la opción -j.
Considere el siguiente ejemplo:
$ objcopy -j.interp test new_test $
El comando anterior realmente copiará solo la sección .interp en el archivo vacío new_test.
Si lo confirmamos:
$ 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.
Entonces vemos que este archivo contiene solo la sección .interp (que copiamos de 'test').
4. Elimine solo una sección en particular del archivo copiado usando la opción -R
Esta opción permite que el comando objdump copie el archivo fuente completo excepto las secciones especificadas junto con esta opción.
Considere el siguiente ejemplo:
$ objcopy -R.interp test new_test
Si confirmamos :
$ objdump -s -j.interp new_test new_test: file format elf64-x86-64
Entonces vemos que no hay ninguna sección .interp en el nuevo archivo 'new_test'.
5. Conservar las fechas de acceso y modificación usando la opción -p
Las fechas de acceso y modificación del archivo copiado se pueden conservar (se pueden mantener igual que la fuente) usando la opción -p junto con este comando.
Considere el siguiente ejemplo:
$ objcopy -p test new_tst
El comando anterior conservará la fecha/hora de acceso y modificación.
Si confirmamos :
$ $ 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
Entonces vemos que se conservó tanto la hora/fecha de acceso como la de modificación.
6. Cambie todos los símbolos globales a débiles usando la opción –debilitar
Esto puede ser útil al crear un archivo de objeto que se puede vincular con otros archivos de objeto utilizando la opción -R para el vinculador.
Considere el siguiente ejemplo:
$ 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 .. $
Entonces vemos que después de ejecutar el comando objcopy con el indicador –debilitar, todos los símbolos GLOBALES se convirtieron en DÉBIL.
7. Símbolos de prefijo con una cadena usando la opción –prefix-symbols
Considere el siguiente ejemplo donde se desea que una cadena 'TGS' tenga el prefijo antes de los nombres de los símbolos:
$ 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 ...
Entonces vemos que 'TGS' fue prefijado antes de los nombres de los símbolos.
8. Elimina un símbolo en particular usando la opción –strip-symbols
En caso de que sea necesario eliminar algunos símbolos, se puede usar la opción –strip-symbols junto con un nombre de archivo. Este nombre de archivo contiene los nombres de los símbolos que se eliminarán (uno en cada línea).
Considere el siguiente ejemplo donde el nombre del símbolo 'call_gmon_start' se eliminará como se especifica en un archivo (nombre del símbolo).
$ 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 ...
Entonces vemos que el símbolo 'call_gmon_start' se eliminó con éxito.
9. Prefije los nombres de las secciones con una cadena usando la opción –prefix-sections
Considere el siguiente ejemplo:
$ 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 ... ... ...
Entonces vemos que el nombre de la sección fue prefijado con nuestra cadena TGS proporcionada.
10. Conservar el símbolo del nombre del archivo de origen mediante la opción –keep-file-symbols
Siempre que se utilice el símbolo –strip-debug (que elimina muchos símbolos relacionados con la depuración junto con el símbolo que especifica el nombre del archivo), si surge la necesidad de conservar el símbolo del nombre del archivo fuente, se pueden utilizar –keep-file-symbols.
Considere el siguiente ejemplo:
$ 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 ...
En el ejemplo anterior, en primer lugar, objcopy se ejecutó con la opción –strip-debug que (junto con muchos otros símbolos) eliminó el símbolo que menciona el nombre del archivo fuente (test.c). A continuación, volvemos a ejecutar el comando objcopy junto con la opción –keep-file-symbols y observamos (en negrita) que el símbolo del nombre del archivo de origen no se eliminó.