当前位置: 首页 > news >正文

fstrict-aliasing

承如“optimization blocks”文中所述,由于相同的指针可能指向相关的内存区,因此编译器将不做过分的优化……

特意搜了下编译器在不同的优化等级下都有哪些默认优化,因此有了此记录(比较长,尽管只讲述了fstrict-aliasing  ……)

下述内容引述自:http://dbp-consulting.com/tutorials/StrictAliasing.html

                           http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html

                           http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule

gcc -v
        gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5)
arm-none-arm-none-linux-gnueabi-gcc -v
        gcc version 4.3.2 (Sourcery G++ Lite 2008q3-72)
首先看下在不同优化等级下gcc的默认优化参数(此处重点关注fstrict-aliasing  在O0(默认优化等级),O2(一般使用时的优化等级)
下的开启情况)
gcc -Q -O0 --help=optimizers -fstrict-aliasing [disabled] arm-gcc -Q -O0 --help=optimizers -fstrict-aliasing [disabled] gcc -Q -O2 --help=optimzers -fstrict-aliasing [enabled] arm-gcc -Q -O0 --help=optimizers -fstrict-aliasing [enabled] 在O0等级下,无论是否显式的添加fstrict-aliasing,fstrict-aliasing都被禁用 在O2等级下,默认开启fstrict-aliasing,可以显式的添加fno-strict-aliasing以禁用fastrict-aliasing

先看下程序和运行结果(分arm与x86)

示例file1.c、
unsigned int swap_words(unsigned int arg)
{
    unsigned short int* const sp = (unsigned short int*)&arg;
    unsigned short int lo = sp[0];
    unsigned short int hi = sp[1];

    sp[0] = hi;
    sp[1] = lo;
    return arg;
}

int main(void)
{
    int x = 0x12345678;
    x = swap_words(x);
    printf("%08x\n", x);
    return 0;
}
gcc -m32 file1.c -o mytest : 56781234
swap_words:
    pushl   %ebp
    movl    %esp,      %ebp
    subl    $16,       %esp
    leal    8(%ebp),   %eax
    movl    %eax,      -8(%ebp)   ;sp
    movl    -8(%ebp),  %eax
    movzwl  (%eax),    %eax       ;arg    
    movw    %ax,       -2(%ebp)   ;arg(l) 
    movl    -8(%ebp),  %eax
    addl    $2,        %eax
    movzwl  (%eax),    %eax
    movw    %ax,       -4(%ebp)   ;arg(h) 
    movl    -8(%ebp),  %eax
    movzwl  -4(%ebp),  %edx
    movw    %dx,       (%eax)     ;arg: arg(h)arg(h)
    movl    -8(%ebp),  %eax
    leal    2(%eax),   %edx
    movzwl  -2(%ebp),  %eax      
    movw    %ax,       (%edx)     ;arg: arg(l)arg(h)
    movl    8(%ebp),   %eax
    leave   
    ret

gcc -m32 -O2 file1.c -o mytest: 12345678
swap_words:
    pushl   %ebp
    movl    %esp,      %ebp
    movzwl  8(%ebp),   %eax      ;arg    
    movzwl  10(%ebp),  %edx      ;arg(h) 
    movw    %ax,       10(%ebp)  ;arg(l)arg(l)
    movl    8(%ebp),   %eax      ;arg(l)arg(l)
    movw    %dx,       8(%ebp)   ;arg(l)arg(h)
    popl    %ebp    
    ret
尽管在swap_words中正确修改了调用者的栈上的值,但是在main中更本就不调用swap_words,
eax的值与我们的原意也不同

gcc -m32 -fno-strict-aliasing -O2 file1.c -o mytest :56781234
swap_words:
    pushl   %ebp
    movl    %esp,      %ebp
    movzwl  8(%ebp),   %eax
    movzwl  10(%ebp),  %edx
    movw    %ax,       10(%ebp)
    movw    %dx,       8(%ebp) 
    movl    8(%ebp),   %eax
    popl    %ebp    
    ret
正确计算了返回值

arm-gcc file1.c -o mytest: 56781234
swap_words:
    str     fp, [sp, #-4]!
    add     fp, sp, #0
    sub     sp, sp, #20 
    str     r0, [fp, #-16]      ;arg
    sub     r3, fp, #16        
    str     r3, [fp, #-12]      ;sp  
    ldr     r3, [fp, #-12]
    ldrh    r3, [r3, #0]        
    strh    r3, [fp, #-8]       ;arg[l]
    ldr     r3, [fp, #-12]
    add     r3, r3, #2
    ldrh    r3, [r3, #0]     
    strh    r3, [fp, #-6]       ;arg[h]
    ldr     r2, [fp, #-12]
    ldrh    r3, [fp, #-6]    
    strh    r3, [r2, #0]        ;arg:arg(l)arg(l)
    ldr     r3, [fp, #-12]
    add     r2, r3, #2
    ldrh    r3, [fp, #-8]    
    strh    r3, [r2, #0]        ;arg:arg(l)arg(h)
    ldr     r3, [fp, #-16]
    mov     r0, r3  
    add     sp, fp, #0
    ldmfd   sp!, {fp}
    bx      lr 

arm-gcc file1.c -O2 -o mytest: 12345678
swap_words:
    sub sp, sp, #8
    str r0, [sp, #4]
    add sp, sp, #8
    bx  lr  
因为实施了fstrict-aliasing优化,因此,swap_words中做了非常大的优化,以至于不做任何计算,直接返回r0

arm-gcc file1.c -O2 -fno-strict-aliasing -o mytest: 56781234
swap_words:
    sub sp, sp, #8
    str r0, [sp, #4]
    ldrh    r3, [sp, #4]
    ldrh    r2, [sp, #6]
    strh    r3, [sp, #6]    @ movhi   
    ldr r0, [sp, #4]
    add sp, sp, #8
    bx  lr  
当我们加上fno-strict-aliasing参数时,swap_words正确计算了返回值,尽管file1.c违背了strict-aliasing规则

先以如上实例阐述一些概念

通过以上的对比分析,我们看到当加入有效的fstrict-aliasing时,编译器做了大量的优化,由于我们的程序违背了strict-aliasing规则,但是这是由于我们程序员自身造成的,与编译器本身的优化无关。那么,如果我们既想编译器做出大量的优化,同时对于违背strict-aliasing规则的程序发出警告,该怎么办了????加入-Wstrict-aliasing编译参.
例如:
arm-none-linux-gnueabi-gcc -O2 -Wstrict-aliasing file1.c -o mytest,会有如下输出:
warning: likely type-punning may break strict-aliasing rules
当我们遇到这类输出时一定要注意(要么我们就使用fno-strict-aliasing参数,例如内核,使用fno-strict-aliasing后只是在某些部分没有做优化,但不会导致编译出的程序与我们的原意相反)


关于c/c++中strict aliasing记录(重点是c)
aliasing is when more than one lvalue refers to the same memory location.

strict aliasing is an assumption, made by the C (or C++) compiler, that dereferencing pointers to objects of different types will never refer to the same memory location. Enable this option in GCC with -fstrict-aliasing flag. Be sure that all code can safely run with this rule enabled. Enable strict aliasing related warnings with -Wstrict-aliasing, but do not expect to be warned in all cases. In order to discover aliasing problems as quickly as possible, -fstrict-aliasing should always be included in the compilation flags for GCC. Otherwise problems may only be visible at the highest optimization levels where it is the most difficult to debug(如果我们使用参数-fno-strict-warning,有些优化将不被实施,而且对于一些潜在的转换错误,编译器不会报出)

the compiler writers know what the strict aliasing rules are for. They are written to let compiler writers known when they can safely assume that a change made through one variable won't affect the value of another variable.
Conversely, the compiler must act very conservatively to access the memory when the compiler cannot assume that two object are not aliased.

在编译选项中加入-fstrict-aliasing的优势在于向编译器说明不同类型的lvalue将指向不相关的内存区域,编译器可以做大量的优化。在编译内核的编译选项CFLAGS中,加入了-fno-strict-aliasing,向编译器表明不同类型的lvalue可能指向相关的内存区域,因此编译器不会做出一些极端的优化而造成不安全(内核编译中优化选项为-O2, -O2优化时默认是-fstrict-aliasing,因此需要显
式的指出编译参数是-fno-strict-aliasing)

1、编译器设计者知道一些左值量会指向相关的内存区域,因此不会做出一些不安全的优化(即使编译选项显式的指出为-fstrict-aliasing,也不会做极端的优化,因为这些类型的左值量有可能指向相关的内存的区域);
2、当我们给编译器加入-fstrict-aliasing选项时,就意味着使用编译器的程序员清晰地向编译器表明:不同类型的左值量不会指向相关的内存区域,编译器可以做出大量的优化,由此产生的不良后果由程序员负责,而非编译器设计者负责;
   当使用-fstrict-aliasing时,有如下基本示例表明不同类型的左值将不会指向相关的内存区域:
   (1)pointers to different built in types do not alias
   (2)pointers to aggregate or union types with differing tags do not alias
   (3)pointers to aggregate or union types which differ only by name may alias

在 1 中提到:一些左值量可能指向相关的内存区域,那么都有哪些可能呢?,如下:                                         
    An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
    (1)— a type compatible with the effective type of the object,
    (2)— a qualified version of a type compatible with the effective type of the object,
    (3)— a type that is the signed or unsigned type corresponding to the effective type of the object,
    (4)— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
    (5)— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
    (6)— a character type.
即:
    (1)Things that are compatible types or differ only by the addition of any combination of signed, unsigned, or volatile. For most purposes compatible type just means the same type. If you want more details you can read the specs. (Example: If you get a pointer to long, and a pointer to const unsigned long they could point to the same thing.)
    (2)An aggregate (struct or class) or union type can alias types contained inside them. (Example: If a function gets passed a pointer to an int, and a pointer to a struct or union containing an int, or possibly containing another struct or union containing an int, or containing...ad infinitum, it's possible that the int* points to an int contained inside the struct or union pointed at by the other pointer.)
    (3)A character type. A char*, signed char*, or unsigned char* is specifically allowed by the specs to point to anything. That means it can alias anything in memory.
    (4)For C++ only, a possibly CV (const and/or volatile) qualified base class type of a dynamic type can alias the child type. (Example: if class dog has class animal for a base class, pointers or references to class dog and class animal can alias.)
    (5)Any lvalue has to be assumed to possibly alias to another lvalue if these rules say that they can alias. An aliasing issue is just as likely to come up with values passed by reference as it is with values passed as pointer to values. Additionally any combination of pointers and references have a possibility of aliasing.

 

看完上面的内容,我们来测试下:

示例file2.c, 此实例验证了上述的第二点(2)

typedef struct
{
    unsigned int a;
    unsigned int b;
    unsigned int c;
}Sample;

void test(unsigned int* values, 
          Sample* uniform, 
          unsigned int count)
{
    unsigned int i = 0;
    for(i = 0; i < count; i++)
    {
        values[i] = (unsigned int)uniform->b;
    }
}

gcc file2.c -o mytest

test:
    pushl   %ebp
    movl    %esp,         %ebp
    subl    $16,          %esp
    movl    $0,           -4(%ebp)       ;i      
    movl    $0,           -4(%ebp)
    jmp .L2 
.L3:
    movl    -4(%ebp),     %eax     ;i
    sall    $2,           %eax
    addl    8(%ebp),      %eax     ;values + 4 * i 
    movl    -4(%ebp),     %edx     ;i
    sall    $2,           %edx
    addl    8(%ebp),      %edx     ;values + 4 * i 
    movl    (%edx),       %ecx
    movl    12(%ebp),     %edx
    movl    4(%edx),      %edx     ;每次重新取得uniform->b
    leal    (%ecx,%edx),  %edx    
    movl    %edx,         (%eax)
    addl    $1,           -4(%ebp)
.L2:
    movl    -4(%ebp),     %eax     ;i      
    cmpl    16(%ebp),     %eax     ;i-count
    jb  .L3 
    leave   
    ret


gcc file2.c -O2 -o mytest
test:
    pushl   %ebp
    movl    %esp,        %ebp
    pushl   %esi
    movl    8(%ebp),     %edx
    pushl   %ebx
    movl    16(%ebp),    %ebx
    movl    12(%ebp),    %esi
    testl   %ebx,        %ebx
    je  .L4 
    xorl    %eax,        %eax
.L3:
    movl    4(%esi),     %ecx   ;每次重新取得uniform->b
    addl    %ecx, (%edx,%eax,4)
    addl    $1,          %eax
    cmpl    %eax,        %ebx
    ja  .L3 
.L4:
    popl    %ebx    
    popl    %esi    
    popl    %ebp    
    ret


arm-gcc file2.c -O2 -o mytest:
test:
    stmfd   sp!, {r4, r5}  
    subs    r5, r2, #0
    mov     r4, r1
    beq     .L4 
    mov     r1, #0
    mov     ip, r1
.L3:
    ldr     r3, [r0, ip]
    ldr     r2, [r4, #4]   ;每次重新取得uniform->b
    add     r1, r1, #1
    add     r3, r3, r2
    cmp     r5, r1
    str     r3, [r0, ip]
    add     ip, ip, #4
    bhi     .L3 
.L4:
    ldmfd   sp!, {r4, r5}
    bx      lr        

=========================================================================

The most commonly accepted method of converting one type of object to another is by
using a union type;
实例file3.c, 
typedef union
{
        unsigned int u32;
        unsigned short int u16[2]; 
}U32;

unsigned int swap_words(unsigned int arg)
{
    U32 in; 
    unsigned short int lo; 
    unsigned short int hi; 

    in.u32 = arg;
    lo = in.u16[0];
    hi = in.u16[1];

    in.u16[0] = hi;
    in.u16[1] = lo;

    return in.u32;
}

gcc file3.c -S -o file3.s
swap_words:
pushl   %ebp
movl    %esp,      %ebp
subl    $16,       %esp
movl    8(%ebp),   %eax       ;arg
movl    %eax,      -8(%ebp)
movzwl  -8(%ebp),  %eax       ;arg
movw    %ax,       -2(%ebp)   ;arg(l) 
movzwl  -6(%ebp),  %eax       ;arg(h) 
movw    %ax,       -4(%ebp)   ;arg(h) 
movzwl  -4(%ebp),  %eax
movw    %ax,       -8(%ebp)   ;arg(h)arg(h)
movzwl  -2(%ebp),  %eax
movw    %ax,       -6(%ebp)   ;arg(l)arg(h)
movl    -8(%ebp),  %eax
leave   
ret


gcc file3.c -O2 -S -o file3.s
既做了优化,有没有错误,验证上述第二点
swap_words:
    pushl   %ebp
    movl    %esp,    %ebp
    movl    8(%ebp), %eax
    popl    %ebp    
    roll    $16,     %eax
    ret

arm-gcc file3.c -S -o file3.s
swap_words:
    str     fp, [sp, #-4]!
    add     fp, sp, #0
    sub     sp, sp, #20 
    str     r0, [fp, #-16]      ;arg
    ldr     r3, [fp, #-16]      ;arg
    str     r3, [fp, #-12]      ;arg
    ldrh    r3, [fp, #-12]      ;arg(l)
    strh    r3, [fp, #-8]       ;arg(l)
    ldrh    r3, [fp, #-10]      ;arg(h)
    strh    r3, [fp, #-6]       ;arg(h)
    ldrh    r3, [fp, #-6]       ;arg(h)
    strh    r3, [fp, #-12]      ;arg(h)arg(h)
    ldrh    r3, [fp, #-8]       ;arg(l)
    strh    r3, [fp, #-10]      ;arg(l)arg(h)
    ldr     r3, [fp, #-12]      ;arg(l)arg(h)
    mov     r0, r3
    add     sp, fp, #0
    ldmfd   sp!, {fp}
    bx      lr  

arm-gcc file3.c -O2 -S -o file3.s
//直接用了循环右移来实现,优化啊!!!
swap_words:
    mov r0, r0, ror #16 
    bx  lr 

=============================================================================

Casting proper may be done between a pointer to a type and a pointer to an aggregate or union type which contains a member of a compatible type;


实例file4.c
unsigned int swap_words(unsigned int arg)
{
    U32* in = (U32*)&arg;
    unsigned short int lo = in->u16[0];
    unsigned short int hi = in->u16[1];

    in->u16[0] = hi;
    in->u16[1] = lo;
    return (in->u32);
}

gcc -S -o file4.s
swap_words:
    pushl   %ebp
    movl    %esp,     %ebp    
    subl    $16,      %esp    
    leal    8(%ebp),  %eax       
    movl    %eax,     -8(%ebp)   ;in
    movl    -8(%ebp), %eax
    movzwl  (%eax),   %eax       ;arg    
    movw    %ax,      -2(%ebp)   ;arg(l)
    movl    -8(%ebp), %eax
    movzwl  2(%eax),  %eax       ;arg(h) 
    movw    %ax,      -4(%ebp)   ;arg(h) 
    movl    -8(%ebp), %eax       ;in     
    movzwl  -4(%ebp), %edx       ;arg(h) 
    movw    %dx,      (%eax)     ;arg(h)arg(h)
    movl    -8(%ebp), %eax       ;in     
    movzwl  -2(%ebp), %edx       ;arg(l) 
    movw    %dx,      2(%eax)    ;arg(l)arg(h)
    movl    -8(%ebp), %eax
    movl    (%eax),   %eax       ;arg(l)arg(h)
    leave   
    ret

gcc -S -O2 -o file4.s
swap_words:
    pushl   %ebp
    movl    %esp,     %ebp    
    movzwl  8(%ebp),  %eax
    movzwl  10(%ebp), %edx
    movw    %ax,      10(%ebp)
    movw    %dx,      8(%ebp)
    movl    8(%ebp),  %eax
    popl    %ebp    
    ret


arm-gcc file4.c -S -o file4.s
swap_words:
    str     fp, [sp, #-4]!
    add     fp, sp, #0
    sub     sp, sp, #20 
    str     r0, [fp, #-16]  ;arg
    sub     r3, fp, #16 
    str     r3, [fp, #-12]  ;in
    ldr     r3, [fp, #-12]
    ldrh    r3, [r3, #0]    ;arg(l)
    strh    r3, [fp, #-8]   ;arg(l)
    ldr     r3, [fp, #-12]   
    ldrh    r3, [r3, #2]    ;arg(h)
    strh    r3, [fp, #-6]   ;arg(h)
    ldr     r2, [fp, #-12]
    ldrh    r3, [fp, #-6]   ;arg(h)
    strh    r3, [r2, #0]    ;arg(h)arg(h)
    ldr     r2, [fp, #-12]
    ldrh    r3, [fp, #-8]   ;arg(l)
    strh    r3, [r2, #2]    ;arg(l)arg(h)
    ldr     r3, [fp, #-12]
    ldr     r3, [r3, #0]    ;arg(l)arg(h)
    mov     r0, r3  
    add     sp, fp, #0
    ldmfd   sp!, {fp}
    bx      lr      

arm-gcc file4.c -O2 -S -o file4.s
swap_words:
    sub     sp, sp, #8
    add     r3, sp, #8
    str     r0, [r3, #-4]!  ;arg
    ldrh    r2, [sp, #4]    ;arg(l)
    ldrh    r1, [r3, #2]    ;arg(h)
    strh    r1, [sp, #4]    ;arg(h)arg(h)
    strh    r2, [r3, #2]    ;arg(l)arg(h)
    ldr     r0, [sp, #4]    ;arg(l)arg(h)
    add     sp, sp, #8
    bx      lr 

============================================================================

实例file5.c(因为对于部分结构来说空间较大,用指针传递)
void swap_words(unsigned int *arg)
{
    U32* combined = (U32*)arg;
    unsigned int start = combined->u32;
    unsigned int lo = start >> 16;
    unsigned int hi = start << 16;

    unsigned int final = lo | hi;

    combined->u32 = final;
}

gcc file5.c -S -o file5.s
swap_words:
    pushl   %ebp
    movl    %esp,       %ebp    
    subl    $32,        %esp    
    movl    8(%ebp),    %eax    
    movl    %eax,       -4(%ebp)  ;combined 
    movl    -4(%ebp),   %eax
    movl    (%eax),     %eax    
    movl    %eax,       -8(%ebp)  ;start  
    movl    -8(%ebp),   %eax
    shrl    $16,        %eax    
    movl    %eax,       -12(%ebp) ;lo
    movl    -8(%ebp),   %eax
    sall    $16,        %eax    
    movl    %eax,       -16(%ebp) ;hi
    movl    -16(%ebp),  %eax      ;hi     
    movl    -12(%ebp),  %edx      ;lo     
    orl     %edx,       %eax      ;hi | lo
    movl    %eax,       -20(%ebp) ;final
    movl    -4(%ebp),   %eax
    movl    -20(%ebp),  %edx
    movl    %edx,       (%eax)    ;combined->u32 = final
    leave   
    ret

gcc file5.c -O2 -S -o file5.s  
swap_words:
    pushl   %ebp
    movl    %esp,    %ebp
    movl    8(%ebp), %eax
    roll    $16,     (%eax)
    popl    %ebp    
    ret

arm-gcc file5.c -S -o file5.s 
swap_words:
    str fp, [sp, #-4]!
    add fp, sp, #0
    sub sp, sp, #36 
    str r0, [fp, #-32]
    ldr r3, [fp, #-32]   
    str r3, [fp, #-24]   ;combined
    ldr r3, [fp, #-24]
    ldr r3, [r3, #0]     
    str r3, [fp, #-20]   ;start
    ldr r3, [fp, #-20]
    mov r3, r3, lsr #16 
    str r3, [fp, #-16]   ;lo
    ldr r3, [fp, #-20]
    mov r3, r3, asl #16 
    str r3, [fp, #-12]   ;hi
    ldr r2, [fp, #-16]
    ldr r3, [fp, #-12]
    orr r3, r2, r3
    str r3, [fp, #-8]    ;final
    ldr r2, [fp, #-24]
    ldr r3, [fp, #-8]
    str r3, [r2, #0]     ;combined->u32 = final
    add sp, fp, #0
    ldmfd   sp!, {fp}
    bx  lr  

arm-gcc file5.c -O2 -S -o file5.s
//注意与file4.c中使用同样编译选项的编译结果的区别(file5.c比较高效,
对于小结构体而言,file3.c同样的编译选项更高效)  
swap_words:
    ldr r3, [r0, #0]
    mov r3, r3, ror #16
    str r3, [r0, #0]
    bx  lr 

==============================================================================

实例file6.c
Occasionally a programmer may encounter the following INVALID method for creating an alias with 
a pointer of a different type: (注意上述(2)的适用范围不包括如下情形) typedef union { unsigned short int* sp; unsigned int* wp; }U32P; unsigned int swap_words(unsigned int arg) { U32P in = {.wp = &arg}; const unsigned int hi = in.sp[1]; const unsigned int lo = in.sp[0]; in.sp[0] = hi; in.sp[1] = lo; return arg; } int main(void) { int x = 0x12345678; int y = swap_words(x); printf("x:%08x y:%08x\n", x, y); return 0; } gcc file6.c -o mytest: 12345678 56781234 swap_words: pushl %ebp movl %esp, %ebp subl $16, %esp movl $0, -4(%ebp) leal 8(%ebp), %eax movl %eax, -4(%ebp) ;wp movl -4(%ebp), %eax ;sp addl $2, %eax ;sp + 2 movzwl (%eax), %eax movzwl %ax, %eax movl %eax, -8(%ebp) ;hi movl -4(%ebp), %eax movzwl (%eax), %eax movzwl %ax, %eax movl %eax, -12(%ebp) ;lo movl -4(%ebp), %eax movl -8(%ebp), %edx ;hi movw %dx, (%eax) ;sp[0] = hi movl -4(%ebp), %eax leal 2(%eax), %edx movl -12(%ebp), %eax movw %ax, (%edx) ;sp[1] = lo movl 8(%ebp), %eax ;lo:hi leave ret gcc file6.c -O2 -o mytest: 12345678 12345678 swap_words: pushl %ebp movl %esp, %ebp movzwl 8(%ebp), %eax ;arg(l) movzwl 10(%ebp), %edx ;arg(h) movw %ax, 10(%ebp) ;arg(l)arg(l) movl 8(%ebp), %eax ;arg(l)arg(l) movw %dx, 8(%ebp) ;arg(l)arg(h) popl %ebp ret 尽管在swap_words中正确修改了调用者的栈上的值,但是在main中更本就不调用用swap_words eax的值与我们的原意也不同 arm-gcc -o mytest : 12345678 56781234 swap_words: str fp, [sp, #-4]! add fp, sp, #0 sub sp, sp, #28 str r0, [fp, #-24] ;arg mov r3, #0 str r3, [fp, #-16] sub r3, fp, #24 str r3, [fp, #-16] ;wp ldr r3, [fp, #-16] ;sp add r3, r3, #2 ldrh r3, [r3, #0] str r3, [fp, #-12] ;hi ldr r3, [fp, #-16] ;sp ldrh r3, [r3, #0] str r3, [fp, #-8] ;lo ldr r2, [fp, #-16] ;sp ldr r3, [fp, #-12] ;hi mov r3, r3, asl #16 mov r3, r3, lsr #16 strh r3, [r2, #0] ;arg(h)arg(h) ldr r3, [fp, #-16] add r2, r3, #2 ldr r3, [fp, #-8] mov r3, r3, asl #16 mov r3, r3, lsr #16 strh r3, [r2, #0] ;arg(l)arg(h) ldr r3, [fp, #-24] ;arg(l)arg(h) mov r0, r3 add sp, fp, #0 ldmfd sp!, {fp} bx lr arm-gcc -O2 -o mytest : 12345678 12345678 swap_words: sub sp, sp, #8 str r0, [sp, #4] add sp, sp, #8 bx lr 因为实施了fstrict-aliasing优化,因此,swap_words中做了非常大的优化,以至于不做任何计算,直接返回r0 The problem with this method is although U32P does in fact say that sp is an alias for wp,
it does not say anything about the relationship between the values pointed to by sp and wp.
This differs in a critical way from the experiment in "file3.c & file4.c" which both define
aliases for the values being pointed to, not the pointers themselves.

=========================================================================

对于上述情形(3)的说明:
It is always presumed that a char* may refer to an alias of any object. It is therefore quite safe, if perhaps a bit unoptimal (for architecture with wide loads and stores) to cast any pointer of any type to a char* type. (即由于char*可能与任何类型的左值相同,因此编译器不会做过分的优化,无论是否指定fstrict-aliasing参数选项都在安全范围内做优化,使用char*带来的问题是可能存在多次load/store,可能会降低性能)

如下代码,使用-O0, 与-O2编译出的程序执行效果相同,都可以交换字内的字节序(注意情形(3))
unsigned int swap_words(unsigned int arg)
{
    char* const cp = (char*)arg;
    const char c0 = cp[0];
    const char c1 = cp[1];
    const char c2 = cp[2];
    const char c3 = cp[3];

    cp[0] = c2;
    cp[1] = c3;
    cp[2] = c0;
    cp[3] = c1;

    return arg;
}

对于情形(3),相反的情况则不一定成立,即:
The converse is not true. Casting a char* to a pointer of any type other than a char* and dereferencing it is usually in volation of the strict aliasing rule.

 

大叔来了,回去洗澡,有点乱,再看看

 

相关文章:

  • mybatis-入门
  • iptables入门 (取自鸟哥的Linux私房菜)
  • Linux(CentOS)安装rar和unrar以及rar和unrar命令的使用
  • Android滑动菜单框架完全解析,教你如何一分钟实现滑动菜单特效
  • 如何解决双显示器显示B/S架构软件的问题
  • c++中将_TCHAR转为string
  • 入门到放弃node系列之Hello Word篇
  • Neither BindingResult nor plain target object f...
  • ios中非ARC项目中引用ARC文件
  • asp.net Mvc Area 找到多个与名为相同的控制器匹配的类型 请通过调用含有“namespaces”参数...
  • MFC连接数据库
  • mina 和 xsocket
  • RHCE 学习笔记(7) 进程管理
  • vSphere基本功能介绍
  • AI 新技术革命将如何重塑就业和全球化格局?深度解读 UN 报告(中篇)
  • Debian下无root权限使用Python访问Oracle
  • export和import的用法总结
  • JS正则表达式精简教程(JavaScript RegExp 对象)
  • macOS 中 shell 创建文件夹及文件并 VS Code 打开
  • Python3爬取英雄联盟英雄皮肤大图
  • tweak 支持第三方库
  • VUE es6技巧写法(持续更新中~~~)
  • 基于MaxCompute打造轻盈的人人车移动端数据平台
  • ------- 计算机网络基础
  • 移动端高清、多屏适配方案
  • ​一些不规范的GTID使用场景
  • "无招胜有招"nbsp;史上最全的互…
  • # Swust 12th acm 邀请赛# [ A ] A+B problem [题解]
  • #我与Java虚拟机的故事#连载05:Java虚拟机的修炼之道
  • $forceUpdate()函数
  • (ZT) 理解系统底层的概念是多么重要(by趋势科技邹飞)
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式
  • (一)SpringBoot3---尚硅谷总结
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)Linux整合apache和tomcat构建Web服务器
  • ***检测工具之RKHunter AIDE
  • *1 计算机基础和操作系统基础及几大协议
  • .NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库
  • .Net IE10 _doPostBack 未定义
  • .Net Remoting(分离服务程序实现) - Part.3
  • .net 开发怎么实现前后端分离_前后端分离:分离式开发和一体式发布
  • .NET学习全景图
  • @FeignClient 调用另一个服务的test环境,实际上却调用了另一个环境testone的接口,这其中牵扯到k8s容器外容器内的问题,注册到eureka上的是容器外的旧版本...
  • [ACTF2020 新生赛]Upload 1
  • [Ariticle] 厚黑之道 一 小狐狸听故事
  • [BZOJ1010] [HNOI2008] 玩具装箱toy (斜率优化)
  • [C#]DataTable常用操作总结【转】
  • [Codeforces] probabilities (R1600) Part.1
  • [CUDA 学习笔记] CUDA kernel 的 grid_size 和 block_size 选择
  • [CVPR2021]Birds of a Feather: Capturing Avian Shape Models from Images
  • [DP 训练] Longest Run on a Snowboard, UVa 10285
  • [HDU5685]Problem A
  • [IDF]啥?
  • [Linux] day07——查看及过滤文本
  • [one_demo_15]模拟交通灯管理系统