comp.lang.ada
 help / color / mirror / Atom feed
From: "Yannick Duchêne (Hibou57)" <yannick_duchene@yahoo.fr>
Subject: Erroneous code generation from GNAT or GCC?
Date: Mon, 29 Apr 2013 00:35:03 +0200
Date: 2013-04-29T00:35:03+02:00	[thread overview]
Message-ID: <op.wv9vopfdule2fv@cardamome> (raw)
In-Reply-To: op.wv7w02pwule2fv@cardamome

Le Sat, 27 Apr 2013 23:08:52 +0200, Yannick Duchêne (Hibou57)  
<yannick_duchene@yahoo.fr> a écrit:

> Hi all,
>
> I will make a stripped‑down version of the case, later. So far I just  
> wonder if any one already encountered a similar case: GNAT not  
> generating any code for a sub‑program. Here what it generates instead,  
> according to the assembly file:
>
>      .cfi_startproc
>      ret
>      .cfi_endproc
>
> […]
> Is this a known bug?

This topic was solved, but in the while, I'm encountering something which  
is frightening me a bit. That's not dropped code, but erroneous code  
generation.

The context: a sub‑program use machine‑code insertion. For convenience and  
avoid errors, this sub‑program is generic. Then, some sub‑program  
instantiate this generic locally, as part of their implementations.

As a remainder, here is the generic using machine‑code insertion:


     function Invoke_3
       (N  : Number_Type;
        P1 : P1_Type;
        P2 : P2_Type;
        P3 : P3_Type)
        return Result_Type
     is
        use System.Machine_Code;
        Result : Result_Type;
     begin

        Asm
          (Template => "int $0x80",
           Outputs => Result_Type'Asm_Output ("=a", Result),
           Inputs =>
             (Number_Type'Asm_Input ("a", N),
              P1_Type'Asm_Input     ("b", P1),
              P2_Type'Asm_Input     ("c", P2),
              P3_Type'Asm_Input     ("d", P3)),
           Volatile => True);

        return Result;

     end Invoke_3;


Now, here is a sample sub‑program instantiating this generic as part of  
its implementation:


     procedure Write (Item : in Character) is

        use Syscall_Numbers;
        use Syscalls;
        use Types;

        Status  : Result_Type;
        Size    : constant Size_Type := (Character'Size / 8);

        function Implementation
           is new Invoke_3
             (P1_Type     => Handle_Type,
              P2_Type     => Address_Type,
              P3_Type     => Size_Type)
              with Inline => True;

     begin
        Status := Implementation
          (N  => NR_write,
           P1 => 1,
           P2 => Item'Address,
           P3 => Size);
     end;


Note `P2`, which is the address argument, goes into ecx (see `Invoke_3`  
above).

This sub‑program will print an ASCII character to the standard output,  
using a Linux system‑call. It will later be changed a bit, to show an  
issue. This one version is working.

Note: so far, `Status` are not interpreted, I know, don't care.

Now, as sample use would be:


     Write ('[');


Note: the platform is 32 bits, so all stack operations are 32 bits  
(push/pop/add and sub on esp).

Here is the generated code for the invocation of the working version:


     movl	$91, (%esp)
     call	library__write__2


First, the character code passed as an argument is written at [esp], the  
the sub‑program in invoked, thus the character code argument is now at  
[esp+4] (32 bits platform).

Now, the generated code of the working version, which is invoked by the  
above:


     library__write__2:
     .LFB7:
        .cfi_startproc
        pushl   %ebx            #
        .cfi_def_cfa_offset 8
        .cfi_offset 3, -8
        subl    $12, %esp       #,
        .cfi_def_cfa_offset 20
        movl    20(%esp), %eax  # item, item
        movb    %al, (%esp)     # item, item
        movl    $1, %edx        #, tmp64
        movl    %esp, %ecx      #, item.19
        movl    $4, %eax        #, tmp63
        movl    %edx, %ebx      # tmp64, tmp64
        int $0x80


Remember when invoked, the argument is tat [esp+4]. The sub‑program pushes  
ebx, so the argument is now at [esp+4]. Then it substract 12 to esp, so  
the argument is now at [esp+20]. Then it reads the value at [esp+20],  
store it in eax, then write eax at [esp], in finally store esp to ecx,  
which is OK, ecx holds the address of the parameter. The system‑call is  
successfully invoked.


Now, change `Write` to that it does not get the address of it's argument,  
but get the address of a local copy of its argument (rather same as above,  
changes are marked):


     procedure Write (Item : in Character) is

        use Syscall_Numbers;
        use Syscalls;
        use Types;

        Element : Character := Item; -- <<< Copy of argument
        Status  : Result_Type;
        Size    : constant Size_Type := (Character'Size / 8);

        function Implementation
           is new Invoke_3
             (P1_Type     => Handle_Type,
              P2_Type     => Address_Type,
              P3_Type     => Size_Type)
              with Inline => True;

     begin
        Status := Implementation
          (N  => NR_write,
           P1 => 1,
           P2 => Element'Address, -- <<< Address of the copy
           P3 => Size);
     end;


This one should behave the same, isn't it? It just store of `Item` to  
local `Element` and so pass `Element'Address` to the system‑call, instead  
of `Item'Address`. Sounds right…


The code generated by GNAT for the invocation part is the same as earlier  
above:


     movl	$91, (%esp)
     call	library__write__2

Still the same, at the entry point of the sub‑program, the argument is at  
[esp+4].

Now, here the code generated for the slightly modified subprogram:


     library__write__2:
     .LFB7:
        .cfi_startproc
        pushl   %ebx            #
        .cfi_def_cfa_offset 8
        .cfi_offset 3, -8
        subl    $24, %esp       #,
        .cfi_def_cfa_offset 32
        movl    $1, %edx        #, tmp65
        leal    15(%esp), %ecx  #, element.19
        movl    $4, %eax        #, tmp64
        movl    %edx, %ebx      # tmp65, tmp65
        int $0x80


As with the previous version, it starts pushing ebx, so the argument is  
now at [esp+8]. Then it substract 24 to esp, so the argument is now at  
[esp+32]. But look at what it stores to ecx: it's the effective address  
(lea is the Intel assembly instruction Load Effective Address)  
corresponding to [esp+15]. This is the wrong address, the good address is  
17 bytes above. Above all, this address does not make any sense, it is not  
even 32 bits aligned. Obviously, the system‑call does not print what's  
expected (it print nothing, probably there is a non‑printable character at  
[esp+15]).

Also note nowhere a copy is made (remember the `Element : constant  
Character := Item;` above).

The generated code looks wrong to me: it does not get the good address, it  
not even a normal address, whatever it did of `Element` as a local copy of  
`Item`.


Sorry for being long with this post, I wanted to provide all the materials  
required to clearly expose the case.


This case makes me remind of an issue I get with GNAT 4.6, when I  
discovered GNATMake was not printing some error messages it should have  
print. I noted according to the GNAT tools sources, the message should  
have been printed, but it was not. Now I wonder if ever GNAT it‑self  
sometimes suffers from a similar bug as above.


-- 
“Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University



  parent reply	other threads:[~2013-04-28 22:35 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-04-27 21:08 GNAT not generating any code for sub‑program: known bug? Yannick Duchêne (Hibou57)
2013-04-27 22:22 ` Yannick Duchêne (Hibou57)
2013-04-27 23:48   ` Yannick Duchêne (Hibou57)
2013-04-28  7:14   ` Simon Wright
2013-04-28 17:52     ` Yannick Duchêne (Hibou57)
2013-04-28 19:27       ` Yannick Duchêne (Hibou57)
2013-04-28 20:46         ` Simon Wright
2013-04-28 20:43       ` Simon Wright
2013-04-28 22:35 ` Yannick Duchêne (Hibou57) [this message]
2013-04-28 22:49   ` Erroneous code generation from GNAT or GCC? Yannick Duchêne (Hibou57)
2013-04-28 23:52   ` Yannick Duchêne (Hibou57)
2013-04-29  1:35     ` Yannick Duchêne (Hibou57)
2013-04-30  0:48       ` Yannick Duchêne (Hibou57)
2013-04-30  6:40         ` Simon Wright
2013-04-30 17:04           ` Yannick Duchêne (Hibou57)
2013-04-30 19:06             ` Simon Wright
2013-04-30 21:28               ` Yannick Duchêne (Hibou57)
2013-04-30 22:22                 ` Simon Wright
2013-05-01 18:19               ` J-P. Rosen
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox