โŒ About FreshRSS

Normal view

There are new articles available, click to refresh the page.
Before yesterdayNews from the Ada programming language world

Ada BFD 1.3.0

20 August 2023 at 14:14
[Ada/ada-bfd-1.3.jpg](Ada/ada-bfd-1.3.jpg)
    1. Integration with Alire

For Linux users only, the Ada BFD(https://github.com/stcarrez/ada-bfd) has an associated Alire crate which allows you to use it easily. To get access to the Alire crate, you should add the AWA Alire index(https://github.com/stcarrez/awa-alire-index) in your Alire configuration as follows:

``` alr index add=https://github.com/stcarrez/awa-alire-index.git name awa ```

Then, you can get access to the crate by using

``` alr with bfdada ```

Let's see how to use this library...

    1. Declarations

The Ada BFD(https://github.com/stcarrez/ada-bfd) library provides a set of Ada bindings that give access to the BFD library. A binary file such as an object file, an executable or an archive is represented by the `Bfd.Files.File_Type` limited type. The symbol table is represented by the `Bfd.Symbols.Symbol_Table` limited type. These two types hold internal data used and managed by the BFD library.

```ada with Bfd.Files; with Bfd.Sections; with Bfd.Symbols; ...

 File    : Bfd.Files.File_Type;
 Symbols : Bfd.Symbols.Symbol_Table;

```

    1. Opening the BFD file

The first step is to use the `Open` procedure to read the object or executable file whose path is given as argument. The `File_Type` parameter will be initialized to get access to the binary file information. The `Check_Format` function must then be called to let the BFD library gather the file format information and verify that it is an object file or an executable.

```ada Bfd.Files.Open (File, Path, ""); if Bfd.Files.Check_Format (File, Bfd.Files.OBJECT) then

   ...

end if; ```

The `File_Type` uses finalization so that it will close and reclaim resources automatically.

    1. Loading the symbol table

The symbol table is loaded by using the `Read_Symbols` procedure.

```ada

  Bfd.Symbols.Read_Symbols (File, Symbols);

```

The resources used by the symbol table will be freed when the symbol table instance is finalized.

    1. Find nearest line

Once the symbol table is loaded, we can use the `Find_Nearest_Line` function to find the nearest line of a function knowing some address. This is almost a part of that function that the addr2line (1)(https://www.man7.org/linux/man-pages/man1/addr2line.1.html) command is using.

```ada File_Name, Func_Name : Ada.Strings.Unbounded.Unbounded_String; Text_Section : Bfd.Sections.Section; Line : Natural; Pc : constant Bfd.Vma_Type := ...; ...

  Text_Section := Bfd.Sections.Find_Section (File, ".text");
  Bfd.Symbols.Find_Nearest_Line (File    => File,
                                 Sec     => Text_Section,
                                 Symbols => Symbols,
                                 Addr    => Pc,
                                 Name    => File_Name,
                                 Func    => Func_Name,
                                 Line    => Line);

```

One tricky aspect of using `Find_Nearest_Line` is the fact that the address we are giving must **sometimes** be converted to an offset within the text region. With Address space layout randomization (ASLR)(https://en.wikipedia.org/wiki/Address_space_layout_randomization) a program is mapped at a random address when it executes. Before calling `Find_Nearest_Line`, we must subtract the base address of the memory region. We must now find the virtual address of the start of the text region that is mapped in memory. While the program is running, you can find the base address of the program by looking at the `/proc/self/maps` file. This special file indicates the list of memory regions used by the process with the addresses, flags and other information. Without ASLR, the program is almost always loaded at the `0x00400000` address.

``` 00400000-007f9000 r-xp 00000000 fd:01 12067645 /home/... 009f8000-009fa000 r--p 003f8000 fd:01 12067645 /home/... 009fa000-00a01000 rw-p 003fa000 fd:01 12067645 /home/... ```

But when it is mapped at a random address, we get a different address each time the program is launched:

``` 55d5983d9000-55d598592000 r--p 00000000 fc:02 1573554 /... 55d598592000-55d599376000 r-xp 001b9000 fc:02 1573554 /... 55d599376000-55d5997ed000 r--p 00f9d000 fc:02 1573554 /... 55d5997ee000-55d5998bb000 r--p 01414000 fc:02 1573554 /... 55d5998bb000-55d5998c6000 rw-p 014e1000 fc:02 1573554 /... ```

In that case, the value to use it the first address of first `r--p` region associated with the program (here `0x55d5983d9000`).

Another method to know the virtual base address is to use the dl_iterate_phdr (3)(https://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html) function and look at the shared objects which are loaded. This function must be executed by the program itself: it gets as parameter a callback function which is called for each loaded shared object and a data parameter that will be passed to the callback.

```

  1. include <dlfcn.h>

static int dl_callback (struct dl_phdr_info* info, size_t size, void* data) {

 /* VM base address is: info->dlpi_addr */
 return 0;

} ...

  dl_iterate_phdr (dl_callback, 0);

```

When the callback is called, you can get the name of the shared object by looking at `info->dlpi_name` and the virtual base address by looking at `info->dlpi_addr`.

Ada BFD(https://github.com/stcarrez/ada-bfd) is a very specific library that is not always easy to use due to the complexity of binary program representation (ELF, DWARF, ...) and program execution. It is however used in very specific contexts such as the Muen Separation Kernel(https://muen.codelabs.ch/) and the Memory Analysis Tool(https://github.com/stcarrez/mat).

Linking error using community edition 2021 on Fedora 36

I have used Ada successfully for years; but I am trying to create "hello world," and I am getting the following error:

/opt/GNAT/2021/bin/../libexec/gcc/x86_64-pc-linux-gnu/10.3.1/ld:
.gnu.build.attributes has both ordered
[.gnu.build.attributes.lo.exit in /lib/../lib64/crt1.o] and unordered
[.gnu.build.attributes in /lib/../lib64/crt1.o] sections
/opt/GNAT/2021/bin/../libexec/gcc/x86_64-pc-linux-gnu/10.3.1/ld:
final link failed: bad value collect2: error: ld returned 1 exit status

New release Ada BFD 1.2.0

11 April 2021 at 18:37

The new release is a cleanup and update of the library to support newer version of GNU binutils. The main changes are below:

  • Cleanup build process and use gprinstall for installation
  • Fix build with binutils > 2.34
  • Remove invalid API: `Bfd.Set_Error_Handler`
  • Remove fake API: `Bfd.Symbols.Is_Local_Label_Name`
    1. Installation

To use the Ada BFD library, you may either build it from the sources ada-bfd-1.2.0.tar.gz(https://download.vacs.fr/ada-bfd/ada-bfd-1.2.0.tar.gz) or install the Debian packages.

To build from the sources, you need to have a working GNAT Ada compiler as well as the `binutils-dev` Debian package installed. Then, run the following commands:

```sh git clone https://github.com/stcarrez/ada-bfd.git cd ada-bfd ./configure make build check install ```

For the Debian package installation, use the configuration that corresponds to your setup:

``` deb https://apt.vacs.fr/ubuntu-bionic bionic main deb https://apt.vacs.fr/ubuntu-focal focal main deb https://apt.vacs.fr/debian-buster buster main ```

and then run:

``` sudo apt-get update

  1. Bionic: sudo apt-get install libbfdada1-dev
  2. Focal: sudo apt-get install libbfdada2-dev
  3. Buster: sudo apt-get install libbfdada3-dev

```

    1. Reading the ELF sections

Using the Ada BFD library in a projet is quite easy, the first step is to add the following line in your GNAT project file:

``` Ada with "bfdada"; ```

To access the information of a binary, you must first define an instance of the `File_Type` and open the file. You will do this as follows:

``` Ada with Bfd.Files;

 ...
 Path : constant String := "..."; --  the binary to load
 File : Bfd.Files.File_Type;
 ...
 Bfd.Files.Open (File, Path, "");

```

Looking at the ELF section is easily made by using the `Section_Iterator` provided by the `Bfd.Sections` package.

```ada with Bfd.Sections;

 ...
 Iter : Bfd.Sections.Section_Iterator := Bfd.Sections.Get_Sections (File);
 ...
 while Bfd.Sections.Has_Element (Iter) loop
   declare
      S   : constant Bfd.Sections.Section := Bfd.Sections.Element (Iter);
   begin
      Ada.Text_IO.Put_Line (Bfd.Sections.Get_Name (S));
   end;
   Bfd.Sections.Next (Iter);
 end loop;

```

The library contains several examples that show different features of the Ada BFD library:

| bfdinfo.adb(https://github.com/stcarrez/ada-bfd/blob/master/samples/bfdinfo.adb) | ./bin/bfdinfo ./bin/bfdgen | Open BFD file, get flags, list sections and symbols | | sections.adb(https://github.com/stcarrez/ada-bfd/blob/master/samples/sections.adb) | ./bin/sections ./bin/bfdgen | Display the ELF sections with the `Bfd.Sections` | | symbol.adb(https://github.com/stcarrez/ada-bfd/blob/master/samples/symbol.adb) | ./bin/symbol ./bin/bfdgen main | Read the symbol table with `Bfd.Symbols` | | disassemble.adb(https://github.com/stcarrez/ada-bfd/blob/master/samples/disassemble.adb) | ./bin/disassemble ./bin/bfdgen | Disassemble the text section with `Bfd.Disassemble` |

GCC 6.1 Ada Compiler From Scratch

29 April 2016 at 12:35

We will do the following tasks:

  1. The binutils build and installation,
  2. The gcc build and installation,
  3. Setting up a default configuration for gprbuild,
  4. The XML/Ada build and installation,
  5. The gprbuild build and installation.

Pre-requisites

First, prepare three distinct directories for the sources, the build materials and the installation. Make sure you have more than 1.5G for the source directory, reserve 7.0G for the build directory and arround 1.5G for the installation directory.

To simplify the commands, define the following shell variables:

BUILD_DIR=<Path of build directory>
INSTALL_DIR=<Path of installation directory>
SRC_DIR=<Path of directory containing the extracted sources>

Also, check that:

  • You have a GNAT Ada compiler installed (at least a 4.9 I guess).
  • You have the gprbuild tool installed and configured for the Ada compiler.
  • You have libmpfr-dev, libgmp3-dev and libgmp-dev installed (otherwise this is far more complex).
  • You have some time and can wait for gcc's compilation (it took more than 2h for me).

Create the directories:

mkdir -p $BUILD_DIR
mkdir -p $INSTALL_DIR/bin
mkdir -p $SRC_DIR

And setup your PATH so that you will use the new binutils and gcc commands while building everything:

export PATH=$INSTALL_DIR/bin:/usr/bin:/bin

Binutils

Download binutils 2.26 and extract the tar.bz2 in the source directory $SRC_DIR.

cd $SRC_DIR
tar xf binutils-2.26.tar.bz2

Never build the binutils within their sources, you must use the $BUILD_DIR for that. Define the installation prefix and configure the binutils as this:

mkdir $BUILD_DIR/binutils
cd $BUILD_DIR/binutils
$SRC_DIR/binutils-2.26/configure --prefix=$INSTALL_DIR

And proceed with the build in the same directory:

make

Compilation is now complete you can install the package:

make install

Gcc

Download gcc 6.1.0 and extract the tar.bz2 in the source directory $SRC_DIR.

cd $SRC_DIR
tar xf gcc-6.1.0.tar.bz2

Again, don't build gcc within its sources and use the $BUILD_DIR directory. At this stage, it is important that your PATH environment variable uses the $INSTALL_DIR/bin first to make sure you will use the new installed binutils tools. You may add the --disable-bootstrap to speed up the build process.

mkdir $BUILD_DIR/gcc
cd $BUILD_DIR/gcc
$SRC_DIR/gcc-6.1.0/configure --prefix=$INSTALL_DIR --enable-languages=c,c++,ada

And proceed with the build in the same directory (go to the restaurant or drink a couple of beers while it builds):

make

Compilation is now complete you can install the package:

make install

The Ada compiler installation does not install two symbolic links which are required during the link phase of Ada libraries and programs. You must create them manually after the install step:

ln -s libgnarl-6.so $INSTALL_DIR/lib/gcc/x86_64-pc-linux-gnu/6.1.0/adalib/libgnarl-6.1.so
ln -s libgnat-6.so $INSTALL_DIR/lib/gcc/x86_64-pc-linux-gnu/6.1.0/adalib/libgnat-6.1.so

Setup the default.cgpr file

The gnatmake command has been deprecated and it is now using gprbuild internally. This means we need a version of gprbuild that uses the new compiler. One way to achieve that is by setting up a gprbuild configuration file:

cd $BUILD_DIR
gprconfig

Select the Ada and C compiler and then edit the default.cgpr file that was generated to change the Toolchain_Version, Runtime_Library_Dir, Runtime_Source_Dir, Driver to indicate the new gcc 6.1 installation paths (replace <INSTALL_DIR> with your installation directory):

configuration project Default is
   ...
   for Toolchain_Version     ("Ada") use "GNAT 6.1";
   for Runtime_Library_Dir   ("Ada") use "<INSTALL_DIR>/lib/gcc/x86_64-pc-linux-gnu/6.1.0//adalib/";
   for Runtime_Source_Dir    ("Ada") use "<INSTALL_DIR>/lib/gcc/x86_64-pc-linux-gnu/6.1.0//adainclude/";
   package Compiler is
      for Driver ("C") use "<INSTALL_DIR>/bin/gcc";
      for Driver ("Ada") use "<INSTALL_DIR>/bin/gcc";
      ...
   end Compiler;
   ...
end Default;

This is the tricky part because if you missed it you may end up using the old Ada compiler. Make sure the Runtime_Library_Dir and Runtime_Source_Dir are correct otherwise you'll have problems during builds. As far as I'm concerned, the gcc target triplet was also changed from x86_64-linux-gnu to x86_64-pc-linux-gnu. Hopefully, once we have built a new gprbuild everything will be easier. The next step is to build XML/Ada which is used by gprbuild.

XML/Ada

Download and extract the XML/Ada sources. Using the git repository works pretty well:

cd $BUILD_DIR
git clone https://github.com/AdaCore/xmlada.git xmlada

This time we must build within the sources. Before running the configure script, the default.cgpr file is installed so that the new Ada compiler is used:

cp $BUILD_DIR/default.cgpr $BUILD_DIR/xmlada/
cd $BUILD_DIR/xmlada
./configure --prefix=$INSTALL_DIR

And proceed with the build in the same directory:

make static shared

Compilation is now complete you can install the package:

make install-static install-relocatable

gprbuild

Get the gprbuild sources from the git repository:

cd $BUILD_DIR
git clone https://github.com/AdaCore/gprbuild.git gprbuild

Copy the default.cgpr file to the gprbuild source tree and run the configure script:

cp $BUILD_DIR/default.cgpr $BUILD_DIR/gprbuild/
cd $BUILD_DIR/gprbuild
./configure --prefix=$INSTALL_DIR

Setup the ADA_PROJECT_PATH environment variable to use the XML/Ada library that was just compiled. If you miss this step, you'll get a file dom.ali is incorrectly formatted error during the bind process.

export ADA_PROJECT_PATH=$INSTALL_DIR/lib/gnat

And proceed with the build in the same directory:

make

Compilation is now complete you can install the package:

make install

Using the compiler

Now you can remove the build directory to make some space. You'll not need the default.cgpr file anymore nor define the ADA_PROJECT_PATH environment variable (except for other needs). To use the new Ada compiler you only need to setup your PATH:

export PATH=$INSTALL_DIR/bin:/usr/bin:/bin

You're now ready to play and use the GCC 6.1 Ada Compiler.

โŒ
โŒ