There are times when you need to port an object file available for one kind of platform (like ARM or x86) to another kind of platform. Things are relatively easy if the source code is available as it can be re-compiled on the target platform. But, what if the source code is not available and you still need to port an object file from type of platform to other? Well, if you are using Linux then the command objcopy does exactly the required. In this article, we will learn the basic usage of this command through some examples.
Since I work only on x86_64 type of platform so I will try to cover some platform neutral functionality of this command in this tutorial.
The syntax of this command is :
objcopy [options] infile [outfile]...
Note that the ‘options’ and ‘outfile’ are not mandatory arguments but have their own significance.
Examples
1. Simply copy object file from source to destination
Consider the following example :
$ objcopy test new_test $
So the above command will copy ‘test’ into a new file ‘new_test’. Note that since in this case, ‘test’ was compiled on the same platform so the output ‘new_test’ will be no different.
Also, if you like to disassemble a binary file and get more details on your object files, you should use objdump command as we explained earlier.
2. Copy the object file without providing the new file name
In the above example, the copied file was named as ‘new_test’ as it was supplied along with options to the command. But, if no destination file name is supplied then the objcopy command replaces the original file with the copied file.
Consider the following example :
$ 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
So we see that the statistics of the object file ‘test’ were completely changed as objcopy created it as a completely new file.
3. Copy only a particular section using -j option
If you wish to copy only one section from source object file to destination object file then -j option is used in this case.
Consider the following example :
$ objcopy -j.interp test new_test $
The above command will actually copy only .interp section into the empty new_test file.
If we confirm it :
$ 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.
So we see that this file contains only .interp section (that we copied from ‘test’ ).
4. Remove only a particular section from the copied file using -R option
This option lets the objdump command to copy the complete source file except the sections specified along with this option.
Consider the following example :
$ objcopy -R.interp test new_test
If we confirm :
$ objdump -s -j.interp new_test new_test: file format elf64-x86-64
So we see that no .interp section is in the new file ‘new_test’.
5. Preserve the access and modification dates using -p option
The access and modification dates of the copied file can be preserved (can be kept same as the source) by using -p option along with this command.
Consider the following example:
$ objcopy -p test new_tst
The above command will preserve the access and modification date/time.
If we confirm :
$ $ 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
So we see that both access and modification time/date was preserved.
6. Change all the global symbols to weak using –weaken option
This can be useful while building an object file that can be linked with other object files using the -R option to the linker.
Consider the following example :
$ 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 .. $
So we see that after running the objcopy command with –weaken flag, all the GLOBAL symbols were converted to WEAK.
7. Prefix symbols with a string using –prefix-symbols option
Consider the following example where a string ‘TGS’ is desired to be prefixed before symbol names :
$ 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 ...
So we see that ‘TGS’ was prefixed before symbol names.
8. Strip off a particular symbols using the –strip-symbols option
In case a some symbols need to be stripped then the option –strip-symbols can be used along with a file name. This file name contains the symbol names to be stripped (one in each line).
Consider the following example where the ‘call_gmon_start’ symbol name will be stripped off as it is specified in a file (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 ...
So we see that the symbol ‘call_gmon_start’ was stripped off successfully.
9. Prefix the section names with a string using –prefix-sections option
Consider the following example :
$ 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 ... ... ...
So we see that the section name was prefixed with our supplied string TGS.
10. Retain source file name symbol using –keep-file-symbols option
Whenever using the –strip-debug symbol (which strips off many debugging related symbols alongwith the symbol specifying file name), if there arises a need to keep the source file name symbol then –keep-file-symbols can be used.
Consider the following example :
$ 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 ...
In the above example, firstly the objcopy was run with –strip-debug option which (along with many other symbols) stripped off the symbol mentioning source file (test.c) name. Next we re-run the objcopy command along with the –keep-file-symbols option and observed (in bold) that symbol for source file name was not stripped off.
Comments on this entry are closed.
good article. Thanks!!!
Thnx for info. Do you know what -O binary does ?
Is it possible to change the type of a symbol?