I don’t believe you’ll find any documents describing why GNAT introduces these <pkg>_E symbols; I guess the developers think you don’t really need to know, and indeed in 20 years of using GNAT I don’t remember ever feeling the need to explore this. You could look at the source (package Sem_Elab looks to have the details).
As for why they’re there, it looks as though it’s to do with checking that a package has been elaborated; looking at a binder-generated package body (b__<main>.adb, or sometimes b~<main>.adb) there’s code like
...
E056 : Short_Integer; pragma Import (Ada, E056, "ada__text_io_E");
...
Ada.Text_Io'Elab_Spec;
Ada.Text_Io'Elab_Body;
E056 := E056 + 1;
...
(E056 is a local name for the two-byte object at address ada__text_io_E) which means "first, elaborate Ada.Text_IO’s spec, then its body, then set a flag to show it’s been fully elaborated".
I’ve not been able to find an example of where this flag has actually been checked, though you can see why it might be needed in this:
package Elaboration is
function F return Integer;
end Elaboration;
package body Elaboration is
Value : Integer;
function F return Integer is (Value);
begin
Value := 42;
end Elaboration;
If Elaboration.F were to be called before the package body had been elaborated, the contents of Value would be undefined.
By default, GNAT goes to considerable lengths to ensure that access-before-elaboration (ABE) doesn’t occur (maybe this explains why there’s actually no generated check in elaboration.o!)