Make Executable Binary File from Elf Using Gnu Objcopy

Make Executable Binary File From Elf Using GNU objcopy

To be executable by the execve(2) syscall, a file usually has to be some elf(5) file (or some script, or some old a.out format). But see also binfmt_misc

Your objcopy(1) command is loosing the essential meta-data in the ELF file. Maybe you want strip(1)

Recall that ELF is quite a complex and versatile format, it specifies the starting address, the interpreter (ld-linux(8) dynamic linker), the several segments of the program etc. All this meta-data is needed by the kernel for execve(2) and is lost with objcopy -O binary ...

When you use objcopy -O binary, you are copying only the binary data:

objcopy can be used to generate a raw binary file by using an output target of `binary' (e.g., use -O binary). When objcopy generates a raw binary file, it will essentially produce a memory dump of the contents of the input object file. All symbols and relocation information will be discarded. The memory dump will start at the load address of the lowest section copied into the output file.

In particular you lose the entry point and the segments list given in the original ELF header. The kernel cannot guess them.

I don't understand why you expect the result of objcopy -O binary to be executable by Linux using execve(2). The main purpose of that objcopy -O binary command is to make firmware or kernel-like stand-alone (or freestanding) binaries, and then you need to exactly understand how they should look like (e.g. what is their starting point, how they are loaded and started) and you probably also use some very specific linker script, and of course that binary cannot contain any syscall to the linux kernel (in particular cannot do any kind of input or output the way a plain Linux executable does them).

Read also more about ABIs, the x86-64 ABI, the Linux Assembly HowTo, the Advanced Linux Programming book.

You probably should read a good OS textbook like Operating System: Three Easy Pieces.

Converting an ELF binary into an .o file

it seems that this is a bit difficult

That's a bit of understatement: for all practical purposes this is impossible to do (at least on ELF platforms), because in the process of linking hello_world the linker discards much of the information that was contained on object files which comprise hello_world, and is necessary to reconstruct it again.

I am trying to add a .rodata section into the binary that I have no source code for

That is unlikely to be your real goal -- the original binary will not use your added .rodata, so your goal must be something else. See also http://xyproblem.info/.

Objcopy elf to bin file

Question 1: What does OBJCOPY=arm-none-eabi-objcopy in this case. I opened the man but I didn't fully undrestand can anyone explain it simply ?

It assigns value arm-none-eabi-objcopy to make variable OBJCOPY.

When make executes this command:

$(OBJCOPY) -O binary $(PROJ_NAME).elf $(PROJ_NAME).bin

the actual command that runs is

arm-none-eabi-objcopy -O binary tim_time_base.elf tim_time_base.bin

Question 2: Flashing the bin file gives the expected result (Leds blinking) However the leds are not blinking by flashing the elf file $(STLINK)/st-flash write $(PROJ_NAME).elf 0x8000000 so why?

The tim_time_base.elf is an ELF file -- it has metadata associated with it. Run arm-none-eabi-readelf -h tim_time_base.elf to see what some of this metadata are.

But when you processor jumps to location 0x8000000 after reset, it is expecting to find executable instructions, not metadata. When it finds "garbage" it doesn't understand, it probably just halts. It certainly doesn't find instructions to blink the lights.

How to convert ELF file to binary file?

In general

An ELF file does not need to use "NO-Fixed memory addresses". In fact, the typical ELF executable file (ET_EXEC) is using a fixed address.

A binary file is usually understood as a file containing non-text data. In the context of programs, it is usually understood to mean the compiled form of the program (in opposition to the source form which is usually a bunch of text files). ELF file are binary files.

Now you might want to know how the ELF file is transformed into the in-memory-representation of the program: the ELF file contains additional information such as where in the program (virtual) address-space each segment of the program should be loaded, which dynamic-libraries should be loaded, how to link the main program and the dynamic libraries together, how to initialise the program, where is the entry point of the program, etc.

One important part of an executable or shared-object is the location of the segments which must be loaded into the program address space. You can look at them using readelf -l:

$ readelf -l /bin/bash

Elf file type is EXEC (Executable file)
Entry point 0x4205bc
There are 9 program headers, starting at offset 64

Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001f8 0x00000000000001f8 R E 8
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x00000000000f1a74 0x00000000000f1a74 R E 200000
LOAD 0x00000000000f1de0 0x00000000006f1de0 0x00000000006f1de0
0x0000000000009068 0x000000000000f298 RW 200000
DYNAMIC 0x00000000000f1df8 0x00000000006f1df8 0x00000000006f1df8
0x0000000000000200 0x0000000000000200 RW 8
NOTE 0x0000000000000254 0x0000000000400254 0x0000000000400254
0x0000000000000044 0x0000000000000044 R 4
GNU_EH_FRAME 0x00000000000d6af0 0x00000000004d6af0 0x00000000004d6af0
0x000000000000407c 0x000000000000407c R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 10
GNU_RELRO 0x00000000000f1de0 0x00000000006f1de0 0x00000000006f1de0
0x0000000000000220 0x0000000000000220 R 1

Each LOAD (PT_LOAD) entry describes a segment which must be loaded in the program address-space.

Reading and processing this information is the job of the ELF loaders: on your typical OS this is done in part by the kernel and in part by the dynamic-linker (ld.so, also called "program interpreter" in ELF parlance).

ARM plain binary files

(I don't really known about ARM stuff.)

You're apparently talking about embedded platforms. On ARM, a plain binary file contains the raw content of the initial memory of the program. It does not contain things such as string tables, symbol tables, relocation tables, debug informations but only the data of the (PT_LOAD) segments.

It is a binary file, not hex-encoded. The vhx files are hex-encoded.

Plain binary files can be generated from the ELF files with fromelf.

The basic idea here is that each PT_LOAD entry of a ELF file is dumped at its correct position in the file and remaining gaps (if any) between them are filled with zeros.

The ELF file already has addresses assigned in the p_vaddr field of each segment so this conversion process does not need to determine addresses: this has already been done by the link editor (and the linker script).

References

  • ARM ELF file format

Embedding binary into elf with objcopy may cause alignment issues?

To answer my own question, I'd assert that objcopy is broken in this instance. I believe that using assembly is likely the best way to go here using Gnu as. Unfortunately I'm now linux machine-less so can't test this properly but I'll put this answer here in case someone finds it or wants to check:

.section ".rodata"
.align 4 # which either means 4 or 2**4 depending on arch!

.global _binary_file_bin_start
.type _binary_file_bin_start, @object
_binary_file_bin_start:
.incbin file.bin

.align 4
.global _binary_file_bin_end
_binary_file_bin_end:

The underscores are the traditional way to annoy yourself with C/asm interoperability. In other words they vanish with MS/Borland compilers under Windows.

C program to open binary elf files, read from them, and print them out (like objcopy)

Here is how you read a file using open() and read().

P.S I used fopen() and fread() instead of open() and read() because I am currently working with a Windows machine. However, the results will be the same for either.


int main()
{
FILE *file = fopen("input.txt", "r");
char buffer[2048];

if (file)
{
/* Loop will continue until an end of file is reached i.e. fread returns 0 elements read */
while (fread(buffer, 4, 1, file) == 1)
{
printf("%s", buffer);
}
fclose(file);
}
}

Update: For interpreting ELF files specifically, I would recommend taking a look at the following resources:

Check out the following code snippet. It shows how you can interpret an ELF file.

#include <stdio.h>
#include <libelf.h>
#include <stdlib.h>
#include <string.h>
static void failure(void);
void main(int argc, char **argv)
{
Elf32_Shdr *shdr;
Elf32_Ehdr *ehdr;
Elf *elf;
Elf_Scn *scn;
Elf_Data *data;
int fd;
unsigned int cnt;

/* Open the input file */
if ((fd = open(argv[1], O_RDONLY)) == -1)
exit(1);

/* Obtain the ELF descriptor */
(void)elf_version(EV_CURRENT);
if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
failure();

/* Obtain the .shstrtab data buffer */
if (((ehdr = elf32_getehdr(elf)) == NULL) ||
((scn = elf_getscn(elf, ehdr->e_shstrndx)) == NULL) ||
((data = elf_getdata(scn, NULL)) == NULL))
failure();

/* Traverse input filename, printing each section */
for (cnt = 1, scn = NULL; scn = elf_nextscn(elf, scn); cnt++)
{
if ((shdr = elf32_getshdr(scn)) == NULL)
failure();
(void)printf("[%d] %s\n", cnt,
(char *)data->d_buf + shdr->sh_name);
}
} /* end main */

static void
failure()
{
(void)fprintf(stderr, "%s\n", elf_errmsg(elf_errno()));
exit(1);
}

I would also recommend checking out the elfutils library, which can be found here.

c# capture raw data from a GNU objcopy process, that dumps to a file

On Windows there is a device "CON" which you might leverage.

objcopy file "someFile" --dump-section .text=CON

I did not test it, because I do not have OBJCOPY, but it worked with OpenSSL. So it should output everything to the console.

huge binary files with objcopy

I found the problem. The objcopy command will try to create the entire address space described in the linker script, from the lowest address to the highest including everything in between. You can tell it to just generate the ROM code as follows:

objcopy ./main.elf -j ROM --output-target=binary ./main.bin

I also changed the linker script slightly

MEMORY {
ram(WXAIL) : ORIGIN = 0x01000000, LENGTH = 32K
rom(RX) : ORIGIN = 0xFFFF0000, LENGTH = 32K
}

SECTIONS {
ROM : {
*(vectors);
*(.text);
*(.rodata);
} > rom

RAM : {
*(.data);
*(.bss);
} > ram
}

Objcopy --writable-text not making elf binary text section writable?

On going through the objcopy man pages for this particular option is is mentioned that the option is not meaningful for all the binary formats. (Is this the reason I am not able to do so ?).

Yes.

At this rather detailed description of special sections of the ELF format, you see that .text has the SHF_ALLOC + SHF_EXECINSTR attributes (has space allocated for it and the space has executable code in it), but not SHF_WRITE (space can be written to). What you are asking objcopy to do simply isn't valid for ELF .text sections.



Related Topics



Leave a reply



Submit