Museum

Home

Lab Overview

Retrotechnology Articles

Online Manuals

⇒ elf_begin(3E) — Reliant UNIX 5.44c4

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

creat(2)

lseek(2)

mmap(2)

open(2)

truncate(3C)

elf(3E)

ar(4)

elf_begin(3E)                                                 elf_begin(3E)

NAME
     elfbegin - make a file descriptor

SYNOPSIS
     cc [flag ...] file ... -lelf [library ...]

     #include <libelf.h>

     Elf *elfbegin(int fildes, ElfCmd cmd, Elf *ref);

DESCRIPTION
     elfbegin(), elfnext(), elfrand(), and elfend() work together to
     process ELF object files, either individually or as members of
     archives. After obtaining an ELF descriptor from elfbegin(), the pro-
     gram may read an existing file, update an existing file, or create a
     new file. fildes is an open file descriptor that elfbegin() uses for
     reading or writing. The initial file offset [see lseek(2)] is uncon-
     strained, and the resulting file offset is undefined.

     cmd may have the following values.

     ELFCNULL
          elfbegin() returns a null pointer, without opening a new
          descriptor. ref is ignored for this command. See elfnext(3E) and
          the associated examples for more information.

     ELFCREAD
          When a program wishes to examine the contents of an existing
          file, it should set cmd to this value. Depending on the value of
          ref, this command examines archive members or entire files. Three
          cases can occur.

          -  If ref is a null pointer, elfbegin() allocates a new ELF
             descriptor and prepares to process the entire file. If the
             file being read is an archive, elfbegin() also prepares the
             resulting descriptor to examine the initial archive member on
             the next call to elfbegin(), as if the program had used
             elfnext() or elfrand() to 'move' to the initial member.

          -  If ref is a non-null descriptor associated with an archive
             file, elfbegin() lets a program obtain a separate ELF
             descriptor associated with an individual member. The program
             should have used elfnext() or elfrand() to position ref
             appropriately (except for the initial member, which
             elfbegin() 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, elfbegin() increments the number of activations for
             the descriptor and returns ref, without allocating a new
             descriptor and without changing the descriptor's read/write



Page 1                       Reliant UNIX 5.44                Printed 11/98

elf_begin(3E)                                                 elf_begin(3E)

             permissions. To terminate the descriptor for ref, the program
             must call elfend() once for each activation. See elfnext(3E)
             and the examples for more information.

     ELFCRDWR
          This command duplicates the actions of ELFCREAD and addition-
          ally allows the program to update the file image [see
          elfupdate(3E)]. That is, using ELFCREAD gives a read-only view
          of the file, while ELFCRDWR lets the program read and write the
          file. ELFCRDWR is not valid for archive members. If ref is
          non-null, it must have been created with the ELFCRDWR command.

     ELFCWRITE
          If the program wishes to ignore previous file contents, presum-
          ably to create a new file, it should set cmd to this value. ref
          is ignored for this command.

     elfbegin() "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 elfkind() or elfgetehdr() 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, elfbegin() returns a
     null pointer. Otherwise, the return value is a non-null ELF descrip-
     tor.

     Before the first call to elfbegin(), a program must call
     elfversion() to coordinate versions.

   System services

     When processing a file, the library decides when to read or write the
     file, depending on the program's requests. Normally, the library
     assumes the file descriptor remains usable for the life of the ELF
     descriptor. If, however, a program must process many files simultane-
     ously and the underlying operating system limits the number of open
     files, the program can use elfcntl() to let it reuse file descrip-
     tors. After calling elfcntl() with appropriate arguments, the program
     may close the file descriptor without interfering with the library.

     All data associated with an ELF descriptor remain allocated until
     elfend() 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 pro-
     gram that deals with multiple input (or output) files must keep the
     ELF descriptors active until it finishes with them.

EXAMPLES
     A prototype for reading a file appears below. If the file is a simple
     object file, the program executes the loop one time, receiving a null
     descriptor in the second iteration. In this case, both elf and arf
     will have the same value, the activation count will be two, and the


Page 2                       Reliant UNIX 5.44                Printed 11/98

elf_begin(3E)                                                 elf_begin(3E)

     program calls elfend() twice to terminate the descriptor. If the file
     is an archive, the loop processes each archive member in turn, ignor-
     ing those that are not object files.

        if (elfversion(EVCURRENT) == EVNONE)
        {
              /* library out of date */
              /* recover from error */
        }
        cmd = ELFCREAD;
        arf = elfbegin(fildes, cmd, (Elf *)0);
        while ((elf = elfbegin(fildes, cmd, arf)) != 0)
        {
              if ((ehdr = elf32getehdr(elf)) != 0)
              {
                      /* process the file ... */
              }
              cmd = elfnext(elf);
              elfend(elf);
        }
        elfend(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 simplicity, 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 elfend() to terminate them.


























Page 3                       Reliant UNIX 5.44                Printed 11/98

elf_begin(3E)                                                 elf_begin(3E)

        elfversion(EVCURRENT);
        arf = elfbegin(fildes, ELFCREAD, (Elf *)0);
        if (elfkind(arf) != ELFKAR)
        {
              /* not an archive */
        }
        /* initial processing */
        /* set offset = ... for desired member header */
        while (elfrand(arf, offset) == offset)
        {
              if ((elf = elfbegin(fildes, ELFCREAD, arf)) == 0)
                 break;
              if ((ehdr = elf32getehdr(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.

        elfversion(EVCURRENT);
        fildes = open("path/name", ORDWROTRUNCOCREAT, 0666);
        if ((elf = elfbegin(fildes, ELFCWRITE, (Elf *)0)) == 0)
              return;
        ehdr = elf32newehdr(elf);
        phdr = elf32newphdr(elf, count);
        scn = elfnewscn(elf);
        shdr = elf32getshdr(scn);
        data = elfnewdata(scn);
        elfupdate(elf, ELFCWRITE);
        elfend(elf);

     Finally, the following outline shows how one might update an existing
     ELF file. Again, this example is simplified to show the overall flow.

        elfversion(EVCURRENT);
        fildes = open("path/name", ORDWR);
        elf = elfbegin(fildes, ELFCRDWR, (Elf *)0);

        /* add new or delete old information ... */

        close(creat("path/name", 0666));
        elfupdate(elf, ELFCWRITE);
        elfend(elf);

     In the example above, the call to creat() truncates the file, thus
     ensuring the resulting file will have the "right" size. Without trun-
     cation, 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(3C)]. Some systems, however, do not


Page 4                       Reliant UNIX 5.44                Printed 11/98

elf_begin(3E)                                                 elf_begin(3E)

     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 descrip-
     tor. Although the library can use a write-only file descriptor, the
     application will not obtain the performance advantages of mmap().

NOTES
     COFF is an object file format that preceded ELF. When a program calls
     elfbegin() on a COFF file, the library translates COFF structures to
     their ELF equivalents, allowing programs to read (but not to write) a
     COFF file as if it were ELF. This conversion happens only to the
     memory image and not to the file itself. After the initial
     elfbegin(), file offsets and addresses in the ELF header, the program
     headers, and the section headers retain the original COFF values (see
     elfgetehdr(), elfgetphdr(), and elfgetshdr()). A program may call
     elfupdate() to adjust these values (without writing the file), and
     the library will then present a consistent, ELF view of the file. Data
     obtained through elfgetdata() are translated (the COFF symbol table
     is presented as ELF, etc.). Data viewed through elfrawdata() undergo
     no conversion, allowing the program to view the bytes from the file
     itself.

     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.

SEE ALSO
     creat(2), lseek(2), mmap(2), open(2), truncate(3C), elf(3E),
     elfcntl(3E), elfend(3E), elfgetarhdr(3E), elfgetbase(3E),
     elfgetdata(3E), elfgetehdr(3E), elfgetphdr(3E), elfgetscn(3E),
     elfkind(3E), elfnext(3E), elfrand(3E), elfrawfile(3E),
     elfupdate(3E), elfversion(3E), ar(4).


















Page 5                       Reliant UNIX 5.44                Printed 11/98

Typewritten Software • bear@typewritten.org • Edmonds, WA 98026