How can I tell GNAT to disable the secondary stack completely on bare-metal Ada code?

t looks like pragma Restrictions (No_Secondary_Stack); does not work for the environment task, according to the documentation fragment below:

3.2.3. Disabling the Secondary Stack

The secondary stack can be disabled by using pragma Restrictions (No_Secondary_Stack); This will cause an error to be raised at compile time for each call to a function that returns an object of unconstrained type. When this restriction is in effect, Ada tasks (excluding the environment task) will not have their secondary stacks allocated.

Does anybody know how I can disable the secondary stack completely, so that not even the environment task can use it?

Thanks,

German Rivera

1 Like

Are you making the runtime or using an existing runtime?

Some untested thoughts:

If you are making it yourself (or have access to recompiling the runtime you are using), you just leave out the files that define the stack (I think s-secsta.ads/b ?). If you are using an existing runtime, it might be tougher. You could see if the linker script defines them and if so remove those definitions, which maybe could cause a linking error if you tried to do anything that requires secondary stack (that includes using tagged types since they return unconstrained objects internally sometimes).

Part of the trouble is that when the binder generates the main program/environment task it includes secondary stack code, and you don’t want to have to build your own gnatbind.

Thanks for the response. I’m using my own bare-minimum runtime. I already removed the s-secsta.ads and s-secsta.adb form my runtime. So, I can catch at compile-time any unwanted calls that return an unconstrained type and thus would cause the use of the secondary stack, and therefore would generate a compiler error. However, I’m hitting runtime crashes on calls like the following:

Str : String (1 .. 8);
Fill_Str (Str);
Foo ("XXXX" & Str);  <-------- runtime crash/hang here apparently caused by stack corruption

Where, Foo has the following signature:

procedure Foo (S : String);

So, it seems that using the "XXXX" & Str expression as a parameter to Foo is placing the resulting string on an uninitialized secondary stack, which corrupts the primary stack?

That’s interesting, I would have expected it to fail at link time since the secondary stack is needed and it doesn’t exist.

This calls the predefined operator

function "&" (Left : in String; Right : in String) return String;

which you don’t allow. For some reason the compiler doesn’t catch this. You’ll need to do

Foo_Front : constant String := "XXXX";
Foo_Arg : String (1 .. Str'Length + Foo_Front'Length);
...
Foo_Arg (Foo_Front'range) := Foo_Front;
Foo_Arg (Foo_Front'Length + 1 .. Foo_Arg'Last) := Str;
Foo (Foo_Arg);
1 Like