头衔几乎说明了一切。有人能给我指点或提供一些代码来可靠地触发gcc最近版本的别名错误吗?我问这个问题的原因是,我试图研究严格混叠的效果,但不管我多么努力地去违反它,gcc总会想出一个“正确”的结果,对你想要违反规则的情况进行任何测试。我并不是在问警告(-WSTINTE-别名=2对我所做的几乎所有事情都会发出警告),而是在使用-fStranced-别名进行优化时实际上会失败的代码。
#include <stdio.h>
#include <stdint.h>
typedef struct mystruct_s {
uint32_t int1;
uint32_t int2;
} mystruct_t;
typedef mystruct_t __attribute__( ( may_alias ) ) mystruct_alias_bad1_t;
// warning: ignoring attributes applied to ‘struct mystruct_s’ after definition [-Wattributes]
// so basically gcc is telling me i have to define it again if want an aliasable
// version?
typedef struct mystruct_alias_s {
uint32_t int1;
uint32_t int2;
} __attribute__( ( may_alias ) ) mystruct_alias_t;
static __attribute__( ( optimize( "no-strict-aliasing" ) ) ) void myfunc1_alias1( void ) {
uint32_t var, *i = &var;
float *f = (float*)&var;
// warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
// so __attribute__( ( optimize( "no-strict-aliasing" ) ) ) is either
// not doing anything or gcc still gives warning even if the
// optimization does not actually happen
*i = 100;
printf( "[test-5] %u", var );
*f = 0.f;
printf( " %u (%s)\n", var, var != 100 ? "OK" : "FAIL" );
}
#pragma GCC optimize "no-strict-aliasing"
static void myfunc1_alias2( void ) {
uint32_t var, *i = &var;
float *f = (float*)&var;
// warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
// this seems to be identical to the
// __attribute__( ( optimize( "no-strict-aliasing" ) ) ) case
*i = 100;
printf( "[test-6] %u", var );
*f = 0.f;
printf( " %u (%s)\n", var, var != 100 ? "OK" : "FAIL" );
}
#pragma GCC optimize "strict-aliasing"
static void myfunc1( void ) {
uint32_t var, *i = &var;
float *f = (float*)&var;
// warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
// conclusion: pretty much none. all 3 functions generate exatcly the same
// code that does just work as expected with no breakage at all despite the
// warning so no-strict-aliasing on a per function level might do nothing
// at all or just not for this code - no way to really tell...
*i = 100;
printf( "[test-7] %u", var );
*f = 0.f;
printf( " %u (%s)\n", var, var != 100 ? "OK" : "FAIL" );
}
int main( int argc, char **argv ) {
unsigned char buf[sizeof( mystruct_t )] = { 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02 };
// obvious rule violation:
printf( "[test-1] int2 == %08X\n",
( (mystruct_t*)buf )->int2
// warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
);
// prints: [test-1] int2 == 2020202
// pretty much the same as above but avoiding the struct:
printf( "[test-2] int1 == %08X, int2 == %08X\n",
*(uint32_t*)buf,
// warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
( (uint32_t*)buf )[1]
// warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
// (you need -Wstrict-aliasing=2 - just -Wstrict-aliasing is not enough)
);
// prints: [test-2] int1 == 1010101, int2 == 2020202
// lets try telling gcc that it should respect what we are trying to do:
printf( "[test-3] int1 == %08X, int2 == %08X\n",
( ( __attribute__( ( may_alias ) ) mystruct_t*)buf )->int1,
// warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
( (mystruct_alias_t*)buf )->int2
// this is the only one that works so far but it seems there is no way
// to cast to such a pointer on the fly - you have to apply this
// attribute to the original struct...
);
// prints: [test-3] int1 == 1010101, int2 == 2020202
// lets try to be creative (basically make a mess with C99 anonymous arrays):
printf( "[test-4] int1 == %08X, int2 == %08X\n",
( ( __attribute__( ( may_alias ) ) mystruct_t* [1] ) { (mystruct_t*)buf } )[0]->int1,
// warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
// (you need -Wstrict-aliasing=2 - just -Wstrict-aliasing is not enough)
// seems the attribute is ignored just as silently as for the direct cast
( ( mystruct_t* [1] ) { (mystruct_t*)buf } )[0]->int2
// warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
// (you need -Wstrict-aliasing=2 - just -Wstrict-aliasing is not enough)
// i guess that evades -Wstrict-aliasing since that seems to pretty
// much seems to only warn about code that casts and dereferences in one
// go
);
// prints: [test-4] int1 == 1010101, int2 == 2020202
// lets try to use __attribute__ optimize to disable strict aliasing temporaly:
myfunc1_alias1();
// lets try pragma:
// #pragma GCC optimize "-fno-strict-aliasing"
// error: #pragma GCC optimize is not allowed inside functions
// (at least if you uncomment that line) so lets try a function again:
myfunc1_alias2();
// lets check if compiling the function without any makeup makes a difference:
myfunc1();
return 0;
}最后编辑:
我现在没有时间更新代码,但我尝试了不同的方法,以避免与提供了以下结果的代码mnunberg进行严格混叠:
__attribute__( ( may_alias ) )工作,但只有当添加到实际的结构定义(似乎并不重要,你选择哪一个)-在其他地方,它被默默地忽略了。
__attribute__( ( optimize( "no-strict-aliasing" ) ) )正如人们所怀疑的那样,这一点也没有影响。程序还挂着。
#pragma GCC optimize "no-strict-aliasing"同样,正如所怀疑的那样,这与上面的相同(没有)。
发布于 2014-05-17 14:54:04
这个程序虽然不是很有用,但很好地证明了GCC的混叠。在优化的代码版本中,GCC看到bp->a从未更改,并优化了整个程序,使其成为一个繁忙的循环:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *a;
char *b;
} s_v;
typedef struct {
char *a;
char *b;
} s_b;
static inline void do_foo(s_v *buf, s_b *bp)
{
buf->a = (char*)0x010;
buf->b = (char*)0x020;
bp->a = buf->a;
bp->b = buf->b;
while (bp->a) {
buf->a--;
}
}
int main(void)
{
s_v *buf = malloc(sizeof (s_v));
s_b *bp = (s_b*)buf;
do_foo(buf, bp);
return 0;
}程序集输出(objdump)
4003c0: eb fe jmp 4003c0 <main>
4003c2: 90 nop
4003c3: 90 nopGCC:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.7/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.7.3-4' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --with-system-zlib --enable-objc-gc --with-cloog --enable-cloog-backend=ppl --disable-cloog-version-check --disable-ppl-version-check --enable-multiarch --with-arch-32=i586 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.7.3 (Debian 4.7.3-4) https://stackoverflow.com/questions/23711613
复制相似问题