|
|
cc [flag . . . ] file . . . -lelf [library] . . .#include <libelf.h>
Elf elf_begin(int fildes, Elf_Cmd cmd, Elf ref);
cmd may have the following values.
First, if ref is a null pointer, elf_begin allocates a new ELF descriptor and prepares to process the entire file. If the file being read is an archive, elf_begin also prepares the resulting descriptor to examine the initial archive member on the next call to elf_begin, as if the program had used elf_next or elf_rand to ``move'' to the initial member.
Second, if ref is a non-null descriptor associated with an archive file, elf_begin lets a program obtain a separate ELF descriptor associated with an individual member. The program should have used elf_next or elf_rand to position ref appropriately (except for the initial member, which elf_begin prepares; see the example below). In this case, fildes should be the same file descriptor used for the parent archive.
Finally, if ref is a non-null ELF descriptor that is not an archive, elf_begin increments the number of activations for the descriptor and returns ref, without allocating a new descriptor and without changing the descriptor's read/write permissions. To terminate the descriptor for ref, the program must call elf_end once for each activation. See elf_next(ELF) and the examples below for more information.
elf_begin ``works'' on all files (including files with zero bytes), providing it can allocate memory for its internal structures and read any necessary information from the file. Programs reading object files thus may call elf_kind or elf_getehdr to determine the file type (only object files have an ELF header). If the file is an archive with no more members to process, or an error occurs, elf_begin returns a null pointer. Otherwise, the return value is a non-null ELF descriptor.
Before the first call to elf_begin, a program must call elf_version to coordinate versions.
All data associated with an ELF descriptor remain allocated until elf_end terminates the descriptor's last activation. After the descriptors have been terminated, the storage is released; attempting to reference such data gives undefined behavior. Consequently, a program that deals with multiple input (or output) files must keep the ELF descriptors active until it finishes with them.
if (elf_version(EV_CURRENT) == EV_NONE) { / library out of date / / recover from error / } cmd = ELF_C_READ; arf = elf_begin(fildes, cmd, (Elf )0); while ((elf = elf_begin(fildes, cmd, arf)) != 0) { if ((ehdr = elf32_getehdr(elf)) != 0) { / process the file . . . / } cmd = elf_next(elf); elf_end(elf); } elf_end(arf);
Alternatively, the next example illustrates random archive processing. After identifying the file as an archive, the program repeatedly processes archive members of interest. For clarity, this example omits error checking and ignores simple object files. Additionally, this fragment preserves the ELF descriptors for all archive members, because it does not call elf_end to terminate them.
elf_version(EV_CURRENT); arf = elf_begin(fildes, ELF_C_READ, (Elf *)0); if (elf_kind(arf) != ELF_K_AR) { / not an archive / } / initial processing / / set offset = . . . for desired member header / while (elf_rand(arf, offset) == offset) { if ((elf = elf_begin(fildes, ELF_C_READ, arf)) == 0) break; if ((ehdr = elf32_getehdr(elf)) != 0) { / process archive member . . . / } / set offset = . . . for desired member header / }
The following outline shows how one might create a new ELF file. This example is simplified to show the overall flow.
elf_version(EV_CURRENT); fildes = open("path/name", O_RDWR|O_TRUNC|O_CREAT, 0666); if ((elf = elf_begin(fildes, ELF_C_WRITE, (Elf )0)) == 0) return; ehdr = elf32_newehdr(elf); phdr = elf32_newphdr(elf, count); scn = elf_newscn(elf); shdr = elf32_getshdr(scn); data = elf_newdata(scn); elf_update(elf, ELF_C_WRITE); elf_end(elf);
Finally, the following outline shows how one might update an existing ELF file. Again, this example is simplified to show the overall flow.
elf_version(EV_CURRENT); fildes = open("path/name", O_RDWR); elf = elf_begin(fildes, ELF_C_RDWR, (Elf )0);/ add new or delete old information . . . /
close(creat("path/name", 0666)); elf_update(elf, ELF_C_WRITE); elf_end(elf);
In the example above, the call to creat truncates the file, thus ensuring the resulting file will have the ``right'' size. Without truncation, the updated file might be as big as the original, even if information were deleted. The library truncates the file, if it can, with ftruncate (see truncate(S)). Some systems, however, do not support ftruncate, and the call to creat protects against this.
Notice that both file creation examples open the file with write and read permissions. On systems that support mmap, the library uses it to enhance performance, and mmap requires a readable file descriptor. Although the library can use a write-only file descriptor, the application will not obtain the performance advantages of mmap.
Some COFF debugging information is not translated, though this does not affect the semantics of a running program.
Although the ELF library supports COFF, programmers are strongly encouraged to recompile their programs, obtaining ELF object files.