In this part, I will continue porting capabilities to the run-time
'Image attribute is used to return the string representation of a value. This value can be integer, boolean, enumeration etc.
The run-time have a separate implementation of the attribute for each supported type. Here is the list of files from my native run-time:
/usr/gnat/lib/gcc/x86_64-pc-linux-gnu/4.9.4/rts-native/adainclude$ lsg img s-imgbiu.adb s-imgbiu.ads s-imgboo.adb s-imgboo.ads s-imgcha.adb s-imgcha.ads s-imgdec.adb s-imgdec.ads s-imgenu.adb s-imgenu.ads s-imgint.adb s-imgint.ads s-imgllb.adb s-imgllb.ads s-imglld.adb s-imglld.ads s-imglli.adb s-imglli.ads s-imgllu.adb s-imgllu.ads s-imgllw.adb s-imgllw.ads s-imgrea.adb s-imgrea.ads s-imguns.adb s-imguns.ads s-imgwch.adb s-imgwch.ads s-imgwiu.adb s-imgwiu.ads
These packages are not preset in our module's run-time, so when attempting to compile something like this:
package body Ada_Foo_Pack is procedure Ada_Foo is S : String := Integer'Image (42) & Character'Val (0); begin Print_Kernel (S); end Ada_Foo; begin null; end Ada_Foo_Pack;
Will result in compiler error:
ada_foo_pack.adb:3:22: construct not allowed in configurable run-time mode ada_foo_pack.adb:3:22: file s-imgint.ads not found ada_foo_pack.adb:3:22: entity "System.Img_Int.Image_Integer" not available
The first step would be to copy one of the native implementations as is.
Unfortunately, the compilation results in the following errors:
s-imgint.adb:75:10: violation of restriction "No_Recursion" at /home/artium/Projects/Ada_Kernel_Module_Toolkit/rts/gnat.adc:18 s-imgint.ads:42:07: violation of restriction "No_Default_Initialization" at /home/artium/Projects/Ada_Kernel_Module_Toolkit/rts/gnat.adc:74
The second violation points to the out parameter
P of the following declaration
procedure Image_Integer (V : Integer; S : in out String; P : out Natural);
After some reading documentation and asking for help at the #ada irc channel, I understood that this violation happens because gnat.adc has both the
No_Default_Initialization restriction and the
As sparre from the irc channel explains, "Normalize_Scalars is a default initialization and you can't override the default initialization of an "out" parameter".
As explained in part 1, the file gnat.c was inherited from the bare bones tutorial. I do not know why the
No_Default_Initialization restriction was added, but
Normalize_Scalars looks pretty useful. Between these two I chose to remove the first one.
This one is simple, the code have a recursion:
procedure Set_Digits (T : Integer; S : in out String; P : in out Natural) is begin if T <= -10 then Set_Digits (T / 10, S, P); P := P + 1; S (P) := Character'Val (48 - (T rem 10)); else P := P + 1; S (P) := Character'Val (48 - T); end if; end Set_Digits;
The following version I wrote does not use recursion:
procedure Set_Digits (T : Integer; S : in out String; P : in out Natural) is D : Natural := 0; -- will store number of digits begin declare T2 : Integer := T; begin while T2 /= 0 loop D := D + 1; T2 := T2 / 10; end loop; end; if D = 0 then P := P + 1; S (P) := '0'; else for I in reverse 0 .. D - 1 loop P := P + 1; S (P) := Character'Val (48 - (T / 10 ** I) rem 10); end loop; end if; end Set_Digits;
The exponent operator I used in the code required copying additional files to the run-time:
It was very tempting to rewrite this package completely, as it is not the most efficient implementation possible and does not use the Ada type system intelligently.
But as I already explained, I am guided by the principle of doing as little changes as possible to the native run-time.
The Unknown Symbol
After the changes made, compiling the module resulted in a warning:
WARNING: "system__img_int__image_integer" [/home/artium/Projects/Ada_Kernel_Module_Toolkit/hello.ko] undefined!
Trying to insert the module resulted in an error:
$sudo insmod hello.ko insmod: ERROR: could not insert module hello.ko: Unknown symbol in module $dmesg | tail -1 [132897.268341] hello: Unknown symbol system__img_int__image_integer (err 0)
It turns out that I forgot to add the run-time lib (
libgnat.a) to the module's makefile. I am a little bit puzzled about why the previous stuff worked.
After adding "
rts/adalib/libgnat.a" to _
hello-y variable, the module loaded and produced the desired output:
$ sudo insmod hello.ko $ dmesg | tail -1 [76863.379199] 42
To make the
Image attribute work with enumeration types I had to copy two additional files from the native run time:
I also had to comment two additional restrictions in the
-- pragma Discard_Names; -- pragma Restrictions (No_Enumeration_Maps);
What happens here is that the compiler will generate the strings and store them in the compiled binary.
When compiling calls to
Some_Type'Image(Some_Value) the compiler will emit a call to an run-time function that will actually do the location of the correct string.
Some_Value can also be a variable, that is why the string must be resolved at run time.
To add support for
Image of real types (fixed and floating point), a bunch of additional files should be copied:
s-exnlli.adb s-exnlli.ads s-expllu.adb s-expllu.ads s-expuns.adb s-expuns.ads s-fatllf.ads s-flocon.adb s-flocon.ads s-imglli.adb s-imglli.ads s-imgllu.adb s-imgllu.ads s-imgrea.adb s-imgrea.ads s-imguns.adb s-imguns.ads s-powtab.ads s-unstyp.ads
I modified one of the file,
s-flocon.adb and removed the import of
__gnat_init_float. The Code that supposed to initialize the FPU does nothing now. I have no problems with that, so far. After all, the Linux kernel should have already did the initialization before our module is being insert.
Additionally a fixed point restriction should be lifted from
-- pragma Restrictions (No_Fixed_Point);
That is all for now. Next I will do
Interfaces package and start binding functions from the Kernel itself.