瀏覽代碼

* align the stack pointer to alignment.localalignmax, fixes crashes on
ARM EABI systems because of a missing 8 byte alignment (mantis
#11595, #13391 and #13454)

git-svn-id: trunk@13030 -

Jonas Maebe 16 年之前
父節點
當前提交
a6f20cdba9
共有 1 個文件被更改,包括 67 次插入94 次删除
  1. 67 94
      compiler/arm/cgcpu.pas

+ 67 - 94
compiler/arm/cgcpu.pas

@@ -1314,8 +1314,11 @@ unit cgcpu;
          firstfloatreg,lastfloatreg,
          r : byte;
          regs : tcpuregisterset;
+         stackmisalignment: pint;
       begin
         LocalSize:=align(LocalSize,4);
+        { call instruction does not put anything on the stack }
+        stackmisalignment:=0;
         if not(nostackframe) then
           begin
             firstfloatreg:=RS_NO;
@@ -1326,6 +1329,7 @@ unit cgcpu;
                   if firstfloatreg=RS_NO then
                     firstfloatreg:=r;
                   lastfloatreg:=r;
+                  inc(stackmisalignment,12);
                 end;
             a_reg_alloc(list,NR_STACK_POINTER_REG);
             if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
@@ -1346,88 +1350,37 @@ unit cgcpu;
               if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
                 include(regs,RS_R14);
             if regs<>[] then
-              list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,regs),PF_FD));
+              begin
+                for r:=RS_R0 to RS_R15 do
+                  if (r in regs) then
+                    inc(stackmisalignment,4);
+                list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,regs),PF_FD));
+              end;
 
             if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
               list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
 
-           (* allocate necessary stack size
-              not necessary according to Yury Sidorov
-
-            { don't use a_op_const_reg_reg here because we don't allow register allocations
-              in the entry/exit code }
-           if (target_info.system in [system_arm_wince]) and
-              (localsize>=winstackpagesize) then
-             begin
-               if localsize div winstackpagesize<=5 then
-                 begin
-                    if is_shifter_const(localsize,shift) then
-                      list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize))
-                    else
-                      begin
-                        a_load_const_reg(list,OS_ADDR,localsize,NR_R12);
-                        list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
-                      end;
-
-                    for i:=1 to localsize div winstackpagesize do
-                      begin
-                        if localsize-i*winstackpagesize<4096 then
-                          reference_reset_base(href,NR_STACK_POINTER_REG,-(localsize-i*winstackpagesize),4)
-                        else
-                          begin
-                            a_load_const_reg(list,OS_ADDR,-(localsize-i*winstackpagesize),NR_R12);
-                            reference_reset_base(href,NR_STACK_POINTER_REG,0,4);
-                            href.index:=NR_R12;
-                          end;
-                        { the data stored doesn't matter }
-                        list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
-                      end;
+            stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
+            if (LocalSize<>0) or
+               ((stackmisalignment<>0) and
+                ((pi_do_call in current_procinfo.flags) or
+                 (po_assembler in current_procinfo.procdef.procoptions))) then
+              begin
+                localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
+                if not(is_shifter_const(localsize,shift)) then
+                  begin
+                    if current_procinfo.framepointer=NR_STACK_POINTER_REG then
+                      a_reg_alloc(list,NR_R12);
+                    a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
+                    list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
                     a_reg_dealloc(list,NR_R12);
-                    reference_reset_base(href,NR_STACK_POINTER_REG,0,4);
-                    { the data stored doesn't matter }
-                    list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
-                 end
-               else
-                 begin
-                    current_asmdata.getjumplabel(again);
-                    list.concat(Taicpu.op_reg_const(A_MOV,NR_R12,localsize div winstackpagesize));
-                    a_label(list,again);
-                    { always shifterop }
-                    list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,winstackpagesize));
-                    reference_reset_base(href,NR_STACK_POINTER_REG,0,4);
-                    { the data stored doesn't matter }
-                    list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
-                    list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_R12,NR_R12,1));
-                    a_jmp_cond(list,OC_NE,again);
-                    if is_shifter_const(localsize mod winstackpagesize,shift) then
-                      list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize mod winstackpagesize))
-                    else
-                      begin
-                        a_load_const_reg(list,OS_ADDR,localsize mod winstackpagesize,NR_R12);
-                        list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
-                      end;
+                  end
+                else
+                  begin
                     a_reg_dealloc(list,NR_R12);
-                    reference_reset_base(href,NR_STACK_POINTER_REG,0,4);
-                    { the data stored doesn't matter }
-                    list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
-                 end
-             end
-            else
-            *)
-            if LocalSize<>0 then
-              if not(is_shifter_const(localsize,shift)) then
-                begin
-                  if current_procinfo.framepointer=NR_STACK_POINTER_REG then
-                    a_reg_alloc(list,NR_R12);
-                  a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
-                  list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
-                  a_reg_dealloc(list,NR_R12);
-                end
-              else
-                begin
-                  a_reg_dealloc(list,NR_R12);
-                  list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
-                end;
+                    list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
+                  end;
+              end;
 
             if firstfloatreg<>RS_NO then
               begin
@@ -1458,9 +1411,11 @@ unit cgcpu;
          shift : byte;
          regs : tcpuregisterset;
          LocalSize : longint;
+         stackmisalignment: pint;
       begin
         if not(nostackframe) then
           begin
+            stackmisalignment:=0;
             { restore floating point register }
             firstfloatreg:=RS_NO;
             { save floating point registers? }
@@ -1470,6 +1425,10 @@ unit cgcpu;
                   if firstfloatreg=RS_NO then
                     firstfloatreg:=r;
                   lastfloatreg:=r;
+                  { floating point register space is already included in
+                    localsize below by calc_stackframe_size
+                   inc(stackmisalignment,12);
+                  }
                 end;
 
             if firstfloatreg<>RS_NO then
@@ -1490,28 +1449,42 @@ unit cgcpu;
                   lastfloatreg-firstfloatreg+1,ref));
               end;
 
+            regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
+            if (pi_do_call in current_procinfo.flags) or (regs<>[]) then
+              begin
+                exclude(regs,RS_R14);
+                include(regs,RS_R15);
+              end;
+            if (current_procinfo.framepointer<>NR_STACK_POINTER_REG) then
+              regs:=regs+[RS_R11,RS_R13,RS_R15];
+
+            for r:=RS_R0 to RS_R15 do
+              if (r in regs) then
+                inc(stackmisalignment,4);
+
+            stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
             if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
               begin
                 LocalSize:=current_procinfo.calc_stackframe_size;
-                if LocalSize<>0 then
-                  if not(is_shifter_const(LocalSize,shift)) then
-                    begin
-                      a_reg_alloc(list,NR_R12);
-                      a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
-                      list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
-                      a_reg_dealloc(list,NR_R12);
-                    end
-                  else
-                    begin
-                      list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
-                    end;
-
-                regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
-                if (pi_do_call in current_procinfo.flags) or (regs<>[]) then
+                if (LocalSize<>0) or
+                   ((stackmisalignment<>0) and
+                    ((pi_do_call in current_procinfo.flags) or
+                     (po_assembler in current_procinfo.procdef.procoptions))) then
                   begin
-                    exclude(regs,RS_R14);
-                    include(regs,RS_R15);
+                    localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
+                    if not(is_shifter_const(LocalSize,shift)) then
+                      begin
+                        a_reg_alloc(list,NR_R12);
+                        a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
+                        list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
+                        a_reg_dealloc(list,NR_R12);
+                      end
+                    else
+                      begin
+                        list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
+                      end;
                   end;
+
                 if regs=[] then
                   list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
                 else
@@ -1527,7 +1500,7 @@ unit cgcpu;
                 { restore int registers and return }
                 reference_reset(ref,4);
                 ref.index:=NR_FRAME_POINTER_REG;
-                list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)+[RS_R11,RS_R13,RS_R15]),PF_EA));
+                list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,regs),PF_EA));
               end;
           end
         else