* rtl.h (struct rtx_def): Update comments.
[official-gcc.git] / gcc / ada / 5omastop.adb
blobf4ce4ced8aa5b6dc0d5e75777a15777de63d22b4
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- SYSTEM.MACHINE_STATE_OPERATIONS --
6 -- --
7 -- B o d y --
8 -- (Version for x86) --
9 -- --
10 -- --
11 -- Copyright (C) 1999-2002 Ada Core Technologies, Inc. --
12 -- --
13 -- GNAT is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 2, or (at your option) any later ver- --
16 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
19 -- for more details. You should have received a copy of the GNU General --
20 -- Public License distributed with GNAT; see file COPYING. If not, write --
21 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
22 -- MA 02111-1307, USA. --
23 -- --
24 -- As a special exception, if other files instantiate generics from this --
25 -- unit, or you link this unit with other files to produce an executable, --
26 -- this unit does not by itself cause the resulting executable to be --
27 -- covered by the GNU General Public License. This exception does not --
28 -- however invalidate any other reasons why the executable file might be --
29 -- covered by the GNU Public License. --
30 -- --
31 -- GNAT was originally developed by the GNAT team at New York University. --
32 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
33 -- --
34 ------------------------------------------------------------------------------
36 -- Note: it is very important that this unit not generate any exception
37 -- tables of any kind. Otherwise we get a nasty rtsfind recursion problem.
38 -- This means no subprograms, including implicitly generated ones.
40 with Unchecked_Conversion;
41 with System.Storage_Elements;
42 with System.Machine_Code; use System.Machine_Code;
43 with System.Memory;
45 package body System.Machine_State_Operations is
47 use System.Exceptions;
49 type Uns8 is mod 2 ** 8;
50 type Uns32 is mod 2 ** 32;
52 type Bits5 is mod 2 ** 5;
53 type Bits6 is mod 2 ** 6;
55 function To_Address is new Unchecked_Conversion (Uns32, Address);
57 type Uns32_Ptr is access all Uns32;
58 function To_Uns32_Ptr is new Unchecked_Conversion (Uns32, Uns32_Ptr);
60 -- Note: the type Uns32 has an alignment of 4. However, in some cases
61 -- values of type Uns32_Ptr will not be aligned (notably in the case
62 -- where we get the immediate field from an instruction). However this
63 -- does not matter in practice, since the x86 does not require that
64 -- operands be aligned.
66 ----------------------
67 -- General Approach --
68 ----------------------
70 -- For the x86 version of this unit, the Subprogram_Info_Type values
71 -- are simply the starting code address for the subprogram. Popping
72 -- of stack frames works by analyzing the code in the prolog, and
73 -- deriving from this analysis the necessary information for restoring
74 -- the registers, including the return point.
76 ---------------------------
77 -- Description of Prolog --
78 ---------------------------
80 -- If a frame pointer is present, the prolog looks like
82 -- pushl %ebp
83 -- movl %esp,%ebp
84 -- subl $nnn,%esp omitted if nnn = 0
85 -- pushl %edi omitted if edi not used
86 -- pushl %esi omitted if esi not used
87 -- pushl %ebx omitted if ebx not used
89 -- If a frame pointer is not present, the prolog looks like
91 -- subl $nnn,%esp omitted if nnn = 0
92 -- pushl %ebp omitted if ebp not used
93 -- pushl %edi omitted if edi not used
94 -- pushl %esi omitted if esi not used
95 -- pushl %ebx omitted if ebx not used
97 -- Note: any or all of the save over call registers may be used and
98 -- if so, will be saved using pushl as shown above. The order of the
99 -- pushl instructions will be as shown above for gcc generated code,
100 -- but the code in this unit does not assume this.
102 -------------------------
103 -- Description of Call --
104 -------------------------
106 -- A call looks like:
108 -- pushl ... push parameters
109 -- pushl ...
110 -- call ... perform the call
111 -- addl $nnn,%esp omitted if no parameters
113 -- Note that we are not absolutely guaranteed that the call is always
114 -- followed by an addl operation that readjusts %esp for this particular
115 -- call. There are two reasons for this:
117 -- 1) The addl can be delayed and combined in the case where more than
118 -- one call appears in sequence. This can be suppressed by using the
119 -- switch -fno-defer-pop and for Ada code, we automatically use
120 -- this switch, but we could still be dealing with C code that was
121 -- compiled without using this switch.
123 -- 2) Scheduling may result in moving the addl instruction away from
124 -- the call. It is not clear if this actually can happen at the
125 -- current time, but it is certainly conceptually possible.
127 -- The addl after the call is important, since we need to be able to
128 -- restore the proper %esp value when we pop the stack. However, we do
129 -- not try to compensate for either of the above effects. As noted above,
130 -- case 1 does not occur for Ada code, and it does not appear in practice
131 -- that case 2 occurs with any significant frequency (we have never seen
132 -- an example so far for gcc generated code).
134 -- Furthermore, it is only in the case of -fomit-frame-pointer that we
135 -- really get into trouble from not properly restoring %esp. If we have
136 -- a frame pointer, then the worst that happens is that %esp is slightly
137 -- more depressed than it should be. This could waste a bit of space on
138 -- the stack, and even in some cases cause a storage leak on the stack,
139 -- but it will not affect the functional correctness of the processing.
141 ----------------------------------------
142 -- Definitions of Instruction Formats --
143 ----------------------------------------
145 type Rcode is (eax, ecx, edx, ebx, esp, ebp, esi, edi);
146 pragma Warnings (Off, Rcode);
147 -- Code indicating which register is referenced in an instruction
149 -- The following define the format of a pushl instruction
151 Op_pushl : constant Bits5 := 2#01010#;
153 type Ins_pushl is record
154 Op : Bits5 := Op_pushl;
155 Reg : Rcode;
156 end record;
158 for Ins_pushl use record
159 Op at 0 range 3 .. 7;
160 Reg at 0 range 0 .. 2;
161 end record;
163 Ins_pushl_ebp : constant Ins_pushl := (Op_pushl, Reg => ebp);
165 type Ins_pushl_Ptr is access all Ins_pushl;
167 -- For the movl %esp,%ebp instruction, we only need to know the length
168 -- because we simply skip past it when we analyze the prolog.
170 Ins_movl_length : constant := 2;
172 -- The following define the format of addl/subl esp instructions
174 Op_Immed : constant Bits6 := 2#100000#;
176 Op2_addl_Immed : constant Bits5 := 2#11100#;
177 pragma Unreferenced (Op2_addl_Immed);
179 Op2_subl_Immed : constant Bits5 := 2#11101#;
181 type Word_Byte is (Word, Byte);
182 pragma Unreferenced (Byte);
184 type Ins_addl_subl_byte is record
185 Op : Bits6; -- Set to Op_Immed
186 w : Word_Byte; -- Word/Byte flag (set to 1 = byte)
187 s : Boolean; -- Sign extension bit (1 = extend)
188 Op2 : Bits5; -- Secondary opcode
189 Reg : Rcode; -- Register
190 Imm8 : Uns8; -- Immediate operand
191 end record;
193 for Ins_addl_subl_byte use record
194 Op at 0 range 2 .. 7;
195 w at 0 range 1 .. 1;
196 s at 0 range 0 .. 0;
197 Op2 at 1 range 3 .. 7;
198 Reg at 1 range 0 .. 2;
199 Imm8 at 2 range 0 .. 7;
200 end record;
202 type Ins_addl_subl_word is record
203 Op : Bits6; -- Set to Op_Immed
204 w : Word_Byte; -- Word/Byte flag (set to 0 = word)
205 s : Boolean; -- Sign extension bit (1 = extend)
206 Op2 : Bits5; -- Secondary opcode
207 Reg : Rcode; -- Register
208 Imm32 : Uns32; -- Immediate operand
209 end record;
211 for Ins_addl_subl_word use record
212 Op at 0 range 2 .. 7;
213 w at 0 range 1 .. 1;
214 s at 0 range 0 .. 0;
215 Op2 at 1 range 3 .. 7;
216 Reg at 1 range 0 .. 2;
217 Imm32 at 2 range 0 .. 31;
218 end record;
220 type Ins_addl_subl_byte_Ptr is access all Ins_addl_subl_byte;
221 type Ins_addl_subl_word_Ptr is access all Ins_addl_subl_word;
223 ---------------------
224 -- Prolog Analysis --
225 ---------------------
227 -- The analysis of the prolog answers the following questions:
229 -- 1. Is %ebp used as a frame pointer?
230 -- 2. How far is SP depressed (i.e. what is the stack frame size)
231 -- 3. Which registers are saved in the prolog, and in what order
233 -- The following data structure stores the answers to these questions
235 subtype SOC is Rcode range ebx .. edi;
236 -- Possible save over call registers
238 SOC_Max : constant := 4;
239 -- Max number of SOC registers that can be pushed
241 type SOC_Push_Regs_Type is array (1 .. 4) of Rcode;
242 -- Used to hold the register codes of pushed SOC registers
244 type Prolog_Type is record
246 Frame_Reg : Boolean;
247 -- This is set to True if %ebp is used as a frame register, and
248 -- False otherwise (in the False case, %ebp may be saved in the
249 -- usual manner along with the other SOC registers).
251 Frame_Length : Uns32;
252 -- Amount by which ESP is decremented on entry, includes the effects
253 -- of push's of save over call registers as indicated above, e.g. if
254 -- the prolog of a routine is:
256 -- pushl %ebp
257 -- movl %esp,%ebp
258 -- subl $424,%esp
259 -- pushl %edi
260 -- pushl %esi
261 -- pushl %ebx
263 -- Then the value of Frame_Length would be 436 (424 + 3 * 4). A
264 -- precise definition is that it is:
266 -- %esp on entry minus %esp after last SOC push
268 -- That definition applies both in the frame pointer present and
269 -- the frame pointer absent cases.
271 Num_SOC_Push : Integer range 0 .. SOC_Max;
272 -- Number of save over call registers actually saved by pushl
273 -- instructions (other than the initial pushl to save the frame
274 -- pointer if a frame pointer is in use).
276 SOC_Push_Regs : SOC_Push_Regs_Type;
277 -- The First Num_SOC_Push entries of this array are used to contain
278 -- the codes for the SOC registers, in the order in which they were
279 -- pushed. Note that this array excludes %ebp if it is used as a frame
280 -- register, since although %ebp is still considered an SOC register
281 -- in this case, it is saved and restored by a separate mechanism.
282 -- Also we will never see %esp represented in this list. Again, it is
283 -- true that %esp is saved over call, but it is restored by a separate
284 -- mechanism.
286 end record;
288 procedure Analyze_Prolog (A : Address; Prolog : out Prolog_Type);
289 -- Given the address of the start of the prolog for a procedure,
290 -- analyze the instructions of the prolog, and set Prolog to contain
291 -- the information obtained from this analysis.
293 ----------------------------------
294 -- Machine_State_Representation --
295 ----------------------------------
297 -- The type Machine_State is defined in the body of Ada.Exceptions as
298 -- a Storage_Array of length 1 .. Machine_State_Length. But really it
299 -- has structure as defined here. We use the structureless declaration
300 -- in Ada.Exceptions to avoid this unit from being implementation
301 -- dependent. The actual definition of Machine_State is as follows:
303 type SOC_Regs_Type is array (SOC) of Uns32;
305 type MState is record
306 eip : Uns32;
307 -- The instruction pointer location (which is the return point
308 -- value from the next level down in all cases).
310 Regs : SOC_Regs_Type;
311 -- Values of the save over call registers
312 end record;
314 for MState use record
315 eip at 0 range 0 .. 31;
316 Regs at 4 range 0 .. 5 * 32 - 1;
317 end record;
318 -- Note: the routines Enter_Handler, and Set_Machine_State reference
319 -- the fields in this structure non-symbolically.
321 type MState_Ptr is access all MState;
323 function To_MState_Ptr is
324 new Unchecked_Conversion (Machine_State, MState_Ptr);
326 ----------------------------
327 -- Allocate_Machine_State --
328 ----------------------------
330 function Allocate_Machine_State return Machine_State is
331 use System.Storage_Elements;
333 begin
334 return Machine_State
335 (Memory.Alloc (MState'Max_Size_In_Storage_Elements));
336 end Allocate_Machine_State;
338 --------------------
339 -- Analyze_Prolog --
340 --------------------
342 procedure Analyze_Prolog (A : Address; Prolog : out Prolog_Type) is
343 Ptr : Address;
344 Ppl : Ins_pushl_Ptr;
345 Pas : Ins_addl_subl_byte_Ptr;
347 function To_Ins_pushl_Ptr is
348 new Unchecked_Conversion (Address, Ins_pushl_Ptr);
350 function To_Ins_addl_subl_byte_Ptr is
351 new Unchecked_Conversion (Address, Ins_addl_subl_byte_Ptr);
353 function To_Ins_addl_subl_word_Ptr is
354 new Unchecked_Conversion (Address, Ins_addl_subl_word_Ptr);
356 begin
357 Ptr := A;
358 Prolog.Frame_Length := 0;
360 if Ptr = Null_Address then
361 Prolog.Num_SOC_Push := 0;
362 Prolog.Frame_Reg := True;
363 return;
364 end if;
366 if To_Ins_pushl_Ptr (Ptr).all = Ins_pushl_ebp then
367 Ptr := Ptr + 1 + Ins_movl_length;
368 Prolog.Frame_Reg := True;
369 else
370 Prolog.Frame_Reg := False;
371 end if;
373 Pas := To_Ins_addl_subl_byte_Ptr (Ptr);
375 if Pas.Op = Op_Immed
376 and then Pas.Op2 = Op2_subl_Immed
377 and then Pas.Reg = esp
378 then
379 if Pas.w = Word then
380 Prolog.Frame_Length := Prolog.Frame_Length +
381 To_Ins_addl_subl_word_Ptr (Ptr).Imm32;
382 Ptr := Ptr + 6;
384 else
385 Prolog.Frame_Length := Prolog.Frame_Length + Uns32 (Pas.Imm8);
386 Ptr := Ptr + 3;
388 -- Note: we ignore sign extension, since a sign extended
389 -- value that was negative would imply a ludicrous frame size.
390 end if;
391 end if;
393 -- Now scan push instructions for SOC registers
395 Prolog.Num_SOC_Push := 0;
397 loop
398 Ppl := To_Ins_pushl_Ptr (Ptr);
400 if Ppl.Op = Op_pushl and then Ppl.Reg in SOC then
401 Prolog.Num_SOC_Push := Prolog.Num_SOC_Push + 1;
402 Prolog.SOC_Push_Regs (Prolog.Num_SOC_Push) := Ppl.Reg;
403 Prolog.Frame_Length := Prolog.Frame_Length + 4;
404 Ptr := Ptr + 1;
406 else
407 exit;
408 end if;
409 end loop;
411 end Analyze_Prolog;
413 -------------------
414 -- Enter_Handler --
415 -------------------
417 procedure Enter_Handler (M : Machine_State; Handler : Handler_Loc) is
418 begin
419 Asm ("mov %0,%%edx", Inputs => Machine_State'Asm_Input ("r", M));
420 Asm ("mov %0,%%eax", Inputs => Handler_Loc'Asm_Input ("r", Handler));
422 Asm ("mov 4(%%edx),%%ebx"); -- M.Regs (ebx)
423 Asm ("mov 12(%%edx),%%ebp"); -- M.Regs (ebp)
424 Asm ("mov 16(%%edx),%%esi"); -- M.Regs (esi)
425 Asm ("mov 20(%%edx),%%edi"); -- M.Regs (edi)
426 Asm ("mov 8(%%edx),%%esp"); -- M.Regs (esp)
427 Asm ("jmp %*%%eax");
428 end Enter_Handler;
430 ----------------
431 -- Fetch_Code --
432 ----------------
434 function Fetch_Code (Loc : Code_Loc) return Code_Loc is
435 begin
436 return Loc;
437 end Fetch_Code;
439 ------------------------
440 -- Free_Machine_State --
441 ------------------------
443 procedure Free_Machine_State (M : in out Machine_State) is
444 begin
445 Memory.Free (Address (M));
446 M := Machine_State (Null_Address);
447 end Free_Machine_State;
449 ------------------
450 -- Get_Code_Loc --
451 ------------------
453 function Get_Code_Loc (M : Machine_State) return Code_Loc is
455 Asm_Call_Size : constant := 2;
456 -- Minimum size for a call instruction under ix86. Using the minimum
457 -- size is safe here as the call point computed from the return point
458 -- will always be inside the call instruction.
460 MS : constant MState_Ptr := To_MState_Ptr (M);
462 begin
463 if MS.eip = 0 then
464 return To_Address (MS.eip);
465 else
466 -- When doing a call the return address is pushed to the stack.
467 -- We want to return the call point address, so we subtract
468 -- Asm_Call_Size from the return address. This value is set
469 -- to 5 as an asm call takes 5 bytes on x86 architectures.
471 return To_Address (MS.eip - Asm_Call_Size);
472 end if;
473 end Get_Code_Loc;
475 --------------------------
476 -- Machine_State_Length --
477 --------------------------
479 function Machine_State_Length
480 return System.Storage_Elements.Storage_Offset
482 begin
483 return MState'Max_Size_In_Storage_Elements;
484 end Machine_State_Length;
486 ---------------
487 -- Pop_Frame --
488 ---------------
490 procedure Pop_Frame
491 (M : Machine_State;
492 Info : Subprogram_Info_Type)
494 MS : constant MState_Ptr := To_MState_Ptr (M);
495 PL : Prolog_Type;
497 SOC_Ptr : Uns32;
498 -- Pointer to stack location after last SOC push
500 Rtn_Ptr : Uns32;
501 -- Pointer to stack location containing return address
503 begin
504 Analyze_Prolog (Info, PL);
506 -- Case of frame register, use EBP, safer than ESP
508 if PL.Frame_Reg then
509 SOC_Ptr := MS.Regs (ebp) - PL.Frame_Length;
510 Rtn_Ptr := MS.Regs (ebp) + 4;
511 MS.Regs (ebp) := To_Uns32_Ptr (MS.Regs (ebp)).all;
513 -- No frame pointer, use ESP, and hope we have it exactly right!
515 else
516 SOC_Ptr := MS.Regs (esp);
517 Rtn_Ptr := SOC_Ptr + PL.Frame_Length;
518 end if;
520 -- Get saved values of SOC registers
522 for J in reverse 1 .. PL.Num_SOC_Push loop
523 MS.Regs (PL.SOC_Push_Regs (J)) := To_Uns32_Ptr (SOC_Ptr).all;
524 SOC_Ptr := SOC_Ptr + 4;
525 end loop;
527 MS.eip := To_Uns32_Ptr (Rtn_Ptr).all;
528 MS.Regs (esp) := Rtn_Ptr + 4;
529 end Pop_Frame;
531 -----------------------
532 -- Set_Machine_State --
533 -----------------------
535 procedure Set_Machine_State (M : Machine_State) is
536 N : constant Asm_Output_Operand := No_Output_Operands;
538 begin
539 Asm ("mov %0,%%edx", N, Machine_State'Asm_Input ("r", M));
541 -- At this stage, we have the following situation (note that we
542 -- are assuming that the -fomit-frame-pointer switch has not been
543 -- used in compiling this procedure.
545 -- (value of M)
546 -- return point
547 -- old ebp <------ current ebp/esp value
549 -- The values of registers ebx/esi/edi are unchanged from entry
550 -- so they have the values we want, and %edx points to the parameter
551 -- value M, so we can store these values directly.
553 Asm ("mov %%ebx,4(%%edx)"); -- M.Regs (ebx)
554 Asm ("mov %%esi,16(%%edx)"); -- M.Regs (esi)
555 Asm ("mov %%edi,20(%%edx)"); -- M.Regs (edi)
557 -- The desired value of ebp is the old value
559 Asm ("mov 0(%%ebp),%%eax");
560 Asm ("mov %%eax,12(%%edx)"); -- M.Regs (ebp)
562 -- The return point is the desired eip value
564 Asm ("mov 4(%%ebp),%%eax");
565 Asm ("mov %%eax,(%%edx)"); -- M.eip
567 -- Finally, the desired %esp value is the value at the point of
568 -- call to this routine *before* pushing the parameter value.
570 Asm ("lea 12(%%ebp),%%eax");
571 Asm ("mov %%eax,8(%%edx)"); -- M.Regs (esp)
572 end Set_Machine_State;
574 ------------------------------
575 -- Set_Signal_Machine_State --
576 ------------------------------
578 procedure Set_Signal_Machine_State
579 (M : Machine_State;
580 Context : System.Address)
582 pragma Warnings (Off, M);
583 pragma Warnings (Off, Context);
585 begin
586 null;
587 end Set_Signal_Machine_State;
589 end System.Machine_State_Operations;