@@ -199,8 +199,14 @@ let reg_str r =
199
199
200
200
(* This is a basic ABI. You might need to customize it by platform. *)
201
201
let (n_hardregs:int ) = 6 ;;
202
- let (n_callee_saves:int ) = 4 ;;
203
202
203
+ (* Includes ebx, esi, edi; does *not* include ebp, which has ABI-specified
204
+ * rules concerning its location and save/restore sequence.
205
+ *
206
+ * See http://refspecs.freestandards.org/elf/abi386-4.pdf
207
+ * Page 36, Figure 3-15 and friends.
208
+ *)
209
+ let (n_callee_saves:int ) = 3 ;;
204
210
205
211
let is_ty32 (ty :Il.scalar_ty ) : bool =
206
212
match ty with
@@ -553,52 +559,61 @@ let wordptr_n (reg:Il.reg) (i:int) : Il.cell =
553
559
554
560
let get_element_ptr = Il. get_element_ptr word_bits reg_str ;;
555
561
556
- let save_callee_saves (e :Il.emitter ) : unit =
562
+ let establish_frame_base (e :Il.emitter ) : unit =
563
+ (* Establish i386-ABI-compliant frame base. *)
557
564
Il. emit e (Il. Push (ro ebp));
565
+ Il. emit e (Il. umov (rc ebp) (ro esp));
566
+ ;;
567
+
568
+ let save_callee_saves (e :Il.emitter ) : unit =
558
569
Il. emit e (Il. Push (ro edi));
559
570
Il. emit e (Il. Push (ro esi));
560
571
Il. emit e (Il. Push (ro ebx));
561
572
;;
562
573
563
-
564
574
let restore_callee_saves (e :Il.emitter ) : unit =
565
575
Il. emit e (Il. Pop (rc ebx));
566
576
Il. emit e (Il. Pop (rc esi));
567
577
Il. emit e (Il. Pop (rc edi));
578
+ ;;
579
+
580
+ let leave_frame (e :Il.emitter ) : unit =
568
581
Il. emit e (Il. Pop (rc ebp));
569
582
;;
570
583
571
584
572
585
(* restores registers from the frame base without updating esp:
573
- * - sets ebp, edi, esi, ebx to stored values from frame base
586
+ * - restores the callee-saves: edi, esi, ebx
587
+ * - restores ebp to stored values from frame base
574
588
* - sets `retpc' register to stored retpc from frame base
575
589
* - sets `base' register to current fp
576
590
*)
577
- let restore_frame_base (e :Il.emitter ) (base :Il.reg ) (retpc :Il.reg ) : unit =
591
+ let restore_frame_regs (e :Il.emitter ) (base :Il.reg ) (retpc :Il.reg )
592
+ : unit =
578
593
let emit = Il. emit e in
579
594
let mov dst src = emit (Il. umov dst src) in
580
595
mov (r base) (ro ebp);
581
- mov (rc ebx) (c (word_at base));
582
- mov (rc esi) (c (word_n base 1 ));
583
- mov (rc edi) (c (word_n base 2 ));
584
- mov (rc ebp) (c (word_n base 3 ));
585
- mov (r retpc) (c (word_n base 4 ));
596
+ mov (rc ebx) (c (word_n base ( - 3 ) ));
597
+ mov (rc esi) (c (word_n base ( - 2 ) ));
598
+ mov (rc edi) (c (word_n base ( - 1 ) ));
599
+ mov (rc ebp) (c (word_at base));
600
+ mov (r retpc) (c (word_n base 1 ));
586
601
;;
587
602
588
603
589
604
(*
590
605
* Our arrangement on x86 is this:
591
606
*
592
- * *ebp+20 +(4*N) = [argN ]
607
+ * *ebp+8 +(4*N) = [argN ]
593
608
* ...
594
- * *ebp+28 = [arg2 ] = obj/closure ptr
595
- * *ebp+24 = [arg1 ] = task ptr
596
- * *ebp+20 = [arg0 ] = out ptr
597
- * *ebp+16 = [retpc ]
598
- * *ebp+12 = [old_ebp]
599
- * *ebp+8 = [old_edi]
600
- * *ebp+4 = [old_esi]
601
- * *ebp = [old_ebx]
609
+ * *ebp+16 = [arg2 ] = obj/closure ptr
610
+ * *ebp+12 = [arg1 ] = task ptr
611
+ * *ebp+8 = [arg0 ] = out ptr
612
+ * *ebp+4 = [retpc ]
613
+ * *ebp = [old_ebp]
614
+ * *ebp-4 = [old_edi]
615
+ * *ebp-8 = [old_esi]
616
+ * *ebp-12 = [old_ebx]
602
617
*
603
618
* For x86-cdecl:
604
619
*
@@ -607,7 +622,7 @@ let restore_frame_base (e:Il.emitter) (base:Il.reg) (retpc:Il.reg) : unit =
607
622
*
608
623
*)
609
624
610
- let frame_base_words = 5 (* eip,ebp,edi,esi,ebx *) ;;
625
+ let frame_base_words = 2 (* eip,ebp *) ;;
611
626
let frame_base_sz = Int64. mul (Int64. of_int frame_base_words) word_sz;;
612
627
613
628
let frame_info_words = 2 (* crate ptr, crate-rel frame info disp *) ;;
@@ -616,6 +631,8 @@ let frame_info_sz = Int64.mul (Int64.of_int frame_info_words) word_sz;;
616
631
let implicit_arg_words = 3 (* task ptr, out ptr, closure ptr *) ;;
617
632
let implicit_args_sz = Int64. mul (Int64. of_int implicit_arg_words) word_sz;;
618
633
634
+ let callee_saves_sz = Int64. mul (Int64. of_int n_callee_saves) word_sz;;
635
+
619
636
let out_ptr = wordptr_n (Il. Hreg ebp) (frame_base_words);;
620
637
let task_ptr = wordptr_n (Il. Hreg ebp) (frame_base_words+ 1 );;
621
638
let closure_ptr = wordptr_n (Il. Hreg ebp) (frame_base_words+ 2 );;
@@ -625,7 +642,8 @@ let ty_param_n i =
625
642
let spill_slot (i :Il.spill ) : Il.mem =
626
643
let imm = (Asm. IMM
627
644
(Int64. neg
628
- (Int64. add frame_info_sz
645
+ (Int64. add
646
+ (Int64. add frame_info_sz callee_saves_sz)
629
647
(Int64. mul word_sz
630
648
(Int64. of_int (i+ 1 ))))))
631
649
in
@@ -664,6 +682,7 @@ let emit_c_call
664
682
let emit = Il. emit e in
665
683
let mov dst src = emit (Il. umov dst src) in
666
684
let imov dst src = emit (Il. imov dst src) in
685
+ let add dst src = emit (Il. binary Il. ADD dst (Il. Cell dst) src) in
667
686
let binary op dst imm = emit (Il. binary op dst (c dst) (immi imm)) in
668
687
669
688
(* rust calls get task as arg0 *)
@@ -735,6 +754,7 @@ let emit_c_call
735
754
emit (Il. call ret fptr);
736
755
mov (rc esp) (c (word_n (h ebp) Abi. task_field_rust_sp));
737
756
mov (rc ebp) (ro esp);
757
+ add (rc ebp) (immi callee_saves_sz);
738
758
739
759
| _ ->
740
760
emit (Il. call ret fptr);
@@ -846,8 +866,10 @@ let crawl_stack_calling_glue
846
866
847
867
mark repeat_jmp_fix;
848
868
849
- mov (rc esi) (c (fp_n (- 1 ))); (* esi <- crate ptr *)
850
- mov (rc edi) (c (fp_n (- 2 ))); (* edi <- frame glue functions. *)
869
+ mov (rc esi) (* esi <- crate ptr *)
870
+ (c (fp_n ((- 1 ) - n_callee_saves)));
871
+ mov (rc edi) (* edi <- frame glue functions. *)
872
+ (c (fp_n ((- 2 ) - n_callee_saves)));
851
873
emit (Il. cmp (ro edi) (immi 0L ));
852
874
853
875
emit
@@ -874,7 +896,7 @@ let crawl_stack_calling_glue
874
896
pop (rc eax);
875
897
876
898
mark skip_jmp_fix;
877
- mov (rc edi) (c (fp_n 3 )); (* load next fp (callee-saves[3]) *)
899
+ mov (rc edi) (c (fp_n 0 )); (* load next fp (fp[0]) *)
878
900
emit (Il. cmp (ro edi) (immi 0L ));
879
901
emit (Il. jmp Il. JE
880
902
(codefix exit_jmp_fix)); (* if nonzero *)
@@ -980,6 +1002,8 @@ let gc_glue
980
1002
(c (edi_n Abi. task_field_rust_sp));
981
1003
982
1004
(* Mark pass. *)
1005
+
1006
+ push (ro ebp);
983
1007
save_callee_saves e;
984
1008
push (ro eax);
985
1009
crawl_stack_calling_glue e Abi. frame_glue_fns_field_mark;
@@ -1005,6 +1029,7 @@ let gc_glue
1005
1029
1006
1030
pop (rc eax);
1007
1031
restore_callee_saves e;
1032
+ pop (rc ebp);
1008
1033
Il. emit e Il. Ret ;
1009
1034
;;
1010
1035
@@ -1182,11 +1207,12 @@ let rec size_calculation_stack_highwater (size:size) : int =
1182
1207
+ 1
1183
1208
;;
1184
1209
1210
+ let minimal_call_sz = Int64. add frame_base_sz callee_saves_sz;;
1185
1211
let boundary_sz =
1186
1212
(Asm. IMM
1187
1213
(Int64. add (* Extra non-frame room: *)
1188
- frame_base_sz (* to safely enter the next frame, *)
1189
- frame_base_sz)) (* and make a 'grow' upcall there. *)
1214
+ minimal_call_sz (* to safely enter the next frame, *)
1215
+ minimal_call_sz)) (* and make a 'grow' upcall there. *)
1190
1216
;;
1191
1217
1192
1218
let stack_growth_check
@@ -1273,8 +1299,8 @@ let minimal_fn_prologue
1273
1299
let sub dst src = emit (Il. binary Il. SUB dst (Il. Cell dst) src) in
1274
1300
1275
1301
(* See diagram and explanation in full_fn_prologue, below. *)
1302
+ establish_frame_base e;
1276
1303
save_callee_saves e;
1277
- mov (rc ebp) (ro esp); (* Establish frame base. *)
1278
1304
sub (rc esp) (imm call_and_frame_sz); (* Establish a frame. *)
1279
1305
mov (rc edi) (ro esp); (* Zero the frame. *)
1280
1306
mov (rc ecx) (imm call_and_frame_sz);
@@ -1329,9 +1355,9 @@ let full_fn_prologue
1329
1355
* | ... |
1330
1356
* | caller arg 0 |
1331
1357
* | retpc | <-- sp we received, top of callee frame
1332
- * | callee save 1 |
1358
+ * | callee save 1 | <-- ebp after frame-base setup
1333
1359
* | ... |
1334
- * | callee save N | <-- ebp and esp after saving callee-saves
1360
+ * | callee save N | <-- esp after saving callee-saves
1335
1361
* | ... |
1336
1362
* | callee frame |
1337
1363
* | + spill |
@@ -1344,19 +1370,20 @@ let full_fn_prologue
1344
1370
* | next save N | <-- bottom of region we must reserve
1345
1371
* | ... |
1346
1372
*
1347
- * A "frame base" is the retpc and set of callee-saves .
1373
+ * A "frame base" is the retpc + ebp .
1348
1374
*
1349
- * We need to reserve room for our frame *and* the next frame-base, because
1350
- * we're going to be blindly entering the next frame-base (pushing eip and
1351
- * callee-saves) before we perform the next check.
1375
+ * We need to reserve room for our frame *and* the next frame-base and
1376
+ * callee-saves, because we're going to be blindly entering the next
1377
+ * frame-base (pushing eip and callee-saves) before we perform the next
1378
+ * check.
1352
1379
*)
1353
1380
1354
1381
(* Already have room to save regs on entry. *)
1382
+ establish_frame_base e;
1355
1383
save_callee_saves e;
1356
1384
1357
1385
let restart_pc = e.Il. emit_pc in
1358
1386
1359
- mov (rc ebp) (ro esp); (* Establish frame base. *)
1360
1387
mov (rc esi) (c task_ptr); (* esi = task *)
1361
1388
mov
1362
1389
(rc esi)
@@ -1444,12 +1471,14 @@ let fn_prologue
1444
1471
;;
1445
1472
1446
1473
let fn_epilogue (e :Il.emitter ) : unit =
1447
-
1448
1474
(* Tear down existing frame. *)
1449
1475
let emit = Il. emit e in
1450
1476
let mov dst src = emit (Il. umov dst src) in
1477
+ let sub dst src = emit (Il. binary Il. SUB dst (Il. Cell dst) src) in
1478
+ sub (rc ebp) (immi callee_saves_sz);
1451
1479
mov (rc esp) (ro ebp);
1452
1480
restore_callee_saves e;
1481
+ leave_frame e;
1453
1482
emit Il. Ret ;
1454
1483
;;
1455
1484
@@ -1543,8 +1572,8 @@ let fn_tail_call
1543
1572
end ;
1544
1573
1545
1574
(* edx <- ebp; restore ebp, edi, esi, ebx; ecx <- retpc *)
1546
- annotate e " tail call: restore callee-saves from frame base" ;
1547
- restore_frame_base e (h edx) (h ecx);
1575
+ annotate e " tail call: restore registers from frame base" ;
1576
+ restore_frame_regs e (h edx) (h ecx);
1548
1577
(* move edx past frame base and adjust for difference in call sizes *)
1549
1578
annotate e " tail call: adjust temporary fp" ;
1550
1579
binary Il. ADD (rc edx) (Int64. add frame_base_sz argsz_diff);
@@ -1637,6 +1666,7 @@ let activate_glue (e:Il.emitter) : unit =
1637
1666
let binary op dst imm = emit (Il. binary op dst (c dst) (immi imm)) in
1638
1667
1639
1668
mov (rc edx) (c (sp_n 1 )); (* edx <- task *)
1669
+ establish_frame_base e;
1640
1670
save_callee_saves e;
1641
1671
mov
1642
1672
(edx_n Abi. task_field_runtime_sp)
@@ -1690,10 +1720,11 @@ let activate_glue (e:Il.emitter) : unit =
1690
1720
*)
1691
1721
1692
1722
binary Il. ADD (edx_n Abi. task_field_rust_sp)
1693
- (Int64. mul (Int64. of_int (n_callee_saves + 1 )) word_sz);
1723
+ (Int64. mul (Int64. of_int (n_callee_saves + 2 )) word_sz);
1694
1724
1695
1725
(* *** IN TASK STACK ****)
1696
1726
restore_callee_saves e;
1727
+ leave_frame e;
1697
1728
emit Il. Ret ;
1698
1729
(* **********************)
1699
1730
()
@@ -1736,6 +1767,7 @@ let yield_glue (e:Il.emitter) : unit =
1736
1767
mov
1737
1768
(rc esp)
1738
1769
(c (edx_n Abi. task_field_rust_sp)); (* esp <- task->rust_sp *)
1770
+ establish_frame_base e;
1739
1771
save_callee_saves e;
1740
1772
mov (* task->rust_sp <- esp *)
1741
1773
(edx_n Abi. task_field_rust_sp)
@@ -1746,6 +1778,7 @@ let yield_glue (e:Il.emitter) : unit =
1746
1778
1747
1779
(* *** IN C STACK ****)
1748
1780
restore_callee_saves e;
1781
+ leave_frame e;
1749
1782
emit Il. Ret ;
1750
1783
(* **********************)
1751
1784
()
@@ -1771,30 +1804,30 @@ let objfile_start
1771
1804
let mov dst src = emit (Il. umov dst src) in
1772
1805
let push_pos32 = push_pos32 e in
1773
1806
Il. emit_full e (Some start_fixup) Il. Dead ;
1807
+ establish_frame_base e;
1774
1808
save_callee_saves e;
1775
- mov (rc ebp) (ro esp);
1776
1809
1777
1810
(* If we're very lucky, the platform will have left us with
1778
1811
* something sensible in the startup stack like so:
1779
1812
*
1780
- * *ebp+24 = [arg1 ] = argv
1781
- * *ebp+20 = [arg0 ] = argc
1782
- * *ebp+16 = [retpc ]
1783
- * *ebp+12 = [old_ebp]
1784
- * *ebp+8 = [old_edi]
1785
- * *ebp+4 = [old_esi]
1786
- * *ebp = [old_ebx]
1813
+ * *ebp+12 = [arg1 ] = argv
1814
+ * *ebp+8 = [arg0 ] = argc
1815
+ * *ebp+4 = [retpc ]
1816
+ * *ebp = [old_ebp]
1817
+ * *ebp-4 = [old_edi]
1818
+ * *ebp-8 = [old_esi]
1819
+ * *ebp-12 = [old_ebx]
1787
1820
*
1788
1821
* This is not the case everywhere, but we start with this
1789
1822
* assumption and correct it in the runtime library.
1790
1823
*)
1791
1824
1792
1825
(* Copy argv. *)
1793
- mov (rc eax) (c (ebp_n ( 2 + n_callee_saves) ));
1826
+ mov (rc eax) (c (ebp_n 3 ));
1794
1827
Il. emit e (Il. Push (ro eax));
1795
1828
1796
1829
(* Copy argc. *)
1797
- mov (rc eax) (c (ebp_n ( 1 + n_callee_saves) ));
1830
+ mov (rc eax) (c (ebp_n 2 ));
1798
1831
Il. emit e (Il. Push (ro eax));
1799
1832
1800
1833
push_pos32 crate_fixup;
@@ -1807,8 +1840,8 @@ let objfile_start
1807
1840
Il. emit e (Il. Pop (rc ecx));
1808
1841
Il. emit e (Il. Pop (rc ecx));
1809
1842
Il. emit e (Il. Pop (rc ecx));
1810
- Il. emit e (Il. umov (rc esp) (ro ebp));
1811
1843
restore_callee_saves e;
1844
+ leave_frame e;
1812
1845
Il. emit e Il. Ret ;
1813
1846
;;
1814
1847
@@ -1847,6 +1880,7 @@ let (abi:Abi.abi) =
1847
1880
Abi. abi_dwarf_fp_reg = dwarf_ebp;
1848
1881
Abi. abi_tp_cell = task_ptr;
1849
1882
Abi. abi_frame_base_sz = frame_base_sz;
1883
+ Abi. abi_callee_saves_sz = callee_saves_sz;
1850
1884
Abi. abi_frame_info_sz = frame_info_sz;
1851
1885
Abi. abi_implicit_args_sz = implicit_args_sz;
1852
1886
Abi. abi_spill_slot = spill_slot;
0 commit comments