≡ Menu

Linux Objcopy Command Examples to Copy and Translate Object Files

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.

Add your comment

If you enjoyed this article, you might also like..

  1. 50 Linux Sysadmin Tutorials
  2. 50 Most Frequently Used Linux Commands (With Examples)
  3. Top 25 Best Linux Performance Monitoring and Debugging Tools
  4. Mommy, I found it! – 15 Practical Linux Find Command Examples
  5. Linux 101 Hacks 2nd Edition eBook Linux 101 Hacks Book

Bash 101 Hacks Book Sed and Awk 101 Hacks Book Nagios Core 3 Book Vim 101 Hacks Book

Comments on this entry are closed.

  • bob January 28, 2013, 8:25 am

    good article. Thanks!!!

  • Alex November 22, 2013, 7:46 am

    Thnx for info. Do you know what -O binary does ?

  • Luke November 25, 2015, 11:16 am

    Is it possible to change the type of a symbol?