Home>

We know that when C is compiled,There are several commonly used optimization compilation options,They are -o0, -o1, -o2, -o3, and -os. I used to think that since it was an optimization option,At most it is to optimize the logic,Improve efficiency or reduce program size.Rarely do they feel that they will affect the end result of the program.Until a bug was found in a program on the arm platform recently, I did not think that these optimization options were sometimes so smart.In other words, it is not so smart for the arm platform.

First look at such a program,This program is my program that simplifies the problem:

#include<stdio.h>
#include<string.h>
int main ()
{
 char buffer [1024]={0,1,2,3,4,5,6,7};
 int itest=0x12345678;
 int * p=(int *) (buffer + 7);
 memcpy (p,&itest, sizeof (itest));
 printf ("%x \ n", buffer [6]);
 printf ("%x \ n", buffer [9]);
 return 0;
}

At first glance,I think there is nothing wrong with this program.Then we call this program file point.c. Then use the cross compilation chain to compile as follows:

arm-xxx-linux-gcc point.c -o point0 -o0
 arm-xxx-linux-gcc point.c -o point1 -o1
 arm-xxx-linux-gcc point.c -o point2 -o2

Finally, three programs are executed separately,The results were a bit unexpected:

./point0
 6
 34
 ./point1
 34
 0
 ./point2
 6
 0

Only in the case of -o0, that is, without optimization,The result was consistent with the hypothesis.But the same problem is no problem on the x86 platform.

So I used the following command,Generate assembly code separately under different optimization options,To determine what went wrong when compiling on the arm platform.

arm-xxx-linux-gcc point.c -o point0.s -o0 -s
 arm-xxx-linux-gcc point.c -o point1.s -o1 -s
 arm-xxx-linux-gcc point.c -o point2.s -o2 -s

Then compare the three compiled codes,Found that the problem lies in the memcpy sentence.

In point0.s, the program is an honest call to memcpy, and then 0x12345678 is honestly placed in the buffer + 7 position one by one.

In point1.s, the program does not call memcpy, but uses the statement:

str r3, [sp, #7]

At this time, r3 is stored in 0x12345678;and because the arm platform I use is 32-bit, when this statement is executed,The address line should not change,So the end result is that the data from buffer + 4 to buffer + 7 is overwritten.Data other than buffer + 7 to buffer + 10 is modified.

In point2.s, it seems that it has been optimized for the pipeline,The program execution order will change,The order of assigning initial values ​​to the parts of the buffer is after str r3, [sp, #7], so the data at buffer + 6 is the correct 6.

Analysis here,Maybe someone would say write a simple program,Will have different results due to different compilation optimization options,Does this memcpy dare not use it?

In fact, as long as you have good programming habits,Will not encounter such problems,For example, the following program:

#include<stdio.h>
#include<string.h>
int main ()
{
 char buffer [1024]={0,1,2,3,4,5,6,7};
 int itest=0x12345678;
 char * p=buffer + 7;
 memcpy (p,&itest, sizeof (itest));
 printf ("%x \ n", buffer [6]);
 printf ("%x \ n", buffer [9]);
 return 0;
}

In fact, this program simply changes the type of p to ensure that under various optimizations,The results are the same.You can see how important good programming habits are.

c
  • Previous Summary of various ways to get Date time in java
  • Next Implementation of login function in Java Struts framework and use of form processor