Tag: gcc

GCC:分段故障和调试程序,仅在优化时崩溃

这是线程的后续跟进: C:分段错误,也许GDB对我说谎 我有一个用-O0编译好的程序,但用-O1,-O2,-O3和Ofast编译段错误。 似乎堆栈在某种程度上会被破坏,但我无法弄清楚为什么或在哪里。 首先,这是我正在使用的结构的一部分。 它位于头文件中: typedef struct { GLuint nsHandle; } OGL_STATE_T; 这是主文件中相关的淡化部分: void init(OGL_STATE_T *state) { printf(“init: %p\n”, state); // Print pointer address make sure it’s the same. compileShaders(state); } int main(argc, char *argv[]) { static OGL_STATE_T _state, *state=&_state; printf(“main: %p\n”, state); // Print pointer address init(state); return 0; } 然后这是compileShaders函数。 这是指针地址损坏发生的地方: void […]

gcc编译器__SIZE_TYPE__

我很好奇由gcc编译器预定义的变量__SIZE_TYPE__ 。 假设我在C中编码如下句子 typedef __SIZE_TYPE__ size_t; 当我使用另一个不包括gcc的C编译器时,是否有可能发生错误? 所有C编译器都有变量__SIZE_TYPE__吗?

ARM + gcc:不要使用一个大的.rodata部分

我想用gcc编译一个带有ARM处理器链接时间优化的程序。 当我在没有LTO的情况下编译时,系统会被编译。 当我启用LTO(使用-flto)时,我得到以下汇编程序错误: 错误:文字常量无效:池需要更近 环顾网络,我发现这与我系统中的常量有关,这些常量放在一个名为.rodata的特殊部分中,它被称为常量池,位于我系统中的.text部分之后。 似乎在使用LTO进行编译时,由于内联和其他优化,这个.rodata部分离指令太远,因此不再可能寻址常量。 是否可以在使用它们的函数之后放置常量? 或者是否可以使用其他寻址模式,以便仍然可以解决.rodata部分? 谢谢。

用于优化的编译器提示和语义

我花了最近几周优化数值算法。 通过预计算,内存对齐,编译器提示和标志以及试错实验的组合,我将运行时间降低了一个数量级。 我还没有使用内在函数或使用multithreading显式向量化。 经常在处理这类问题时,会有一个初始化例程,在此之后,许多参数变为常量。 这些可能是filter长度,switch语句的表达式,循环长度或迭代增量。 如果在编译时知道参数,编译器应该能够通过确切地知道如何展开循环,用指令中具有偏移量的指令替换索引计算来简化或消除表达式,从而更有效地进行优化。编译时,可能消除switch语句等。处理这个问题的最极端的方法是运行初始化例程(在运行时),然后在关键函数上运行编译器,使用某种插件进行优化允许迭代抽象语法树,用常量替换参数,最后动态链接到共享对象。 如果例程很短,可以使用许多工具在二进制文件中动态编译。 更实际的是,我非常依赖于对齐,gcc __builtin_assume_aligned,restrict,手动循环展开和编译器标志,以便编译器在编译时给定参数的未知值来执行我想要的操作。 我想知道还有哪些其他选项至少接近便携式。 我只使用内在函数作为最后的手段,因为它不便携并且工作量很大。 具体来说,如何使用语言语义,编译器扩展或外部工具为编译器(gcc)提供有关循环变量的附加信息,以便它可以更好地为我做优化。 类似地,有任何方法可以将变量限定为具有步幅,以便加载和存储始终对齐,从而更容易启用自动矢量化和循环展开过程。 这些问题经常出现,所以我希望有更优雅的解决方法。 以下是我手工优化的问题的例子,但我相信编译器应该能够为我做。 这些不是进一步的问题。 有时你有一个滤波器,其长度不是最长SIMD寄存器长度的倍数,也可能存在内存对齐问题。 在这种情况下,我要么(A)通过向量寄存器的倍数展开循环并调用结果/序言的未优化代码,或者(B)用零填充filter的开始或结束。 我最近学会了gcc和其他编译器有能力剥离循环。 从我能够找到的有限文档中,我相信使用编译器指令,你对剥离的最好的颗粒控制是整个函数(而不是单个循环)。 此外,您可以提供一些参数,但它主要只是展开量或生成的指令数的上限或下限。 为了真正了解展开/剥离或零填充的最佳方法,编译器需要了解循环的长度和/或增量的大小。 例如,知道循环可能长度大于一百万或小于100将是非常有帮助的。知道循环将总是运行32或34次将是有帮助的。 实际上,由于编译器比我更了解计算机体系结构,如果它根据我提供的有关循环变量的信息做出所有展开决策,会好得多。 我有一种情况,我希望编译器展开循环。 我特意给它了#pragma GCC optimize (“unroll-loops”)指令。 然而,它需要工作的也是语句N &= ~7 ,从而通知编译器循环长度是8的倍数。这不是语言的语义特征,并且它没有改变的效果N的值。严格地告知静态分析器编译器循环已经是AVX寄存器长度的倍数。 在这种情况下,我很幸运,它很有效,因为gcc非常聪明。 但在其他情况下,我的提示似乎不起作用(或者他们这样做,但是没有编译器反馈让我知道附加信息没有价值)。 在一种情况下,我必须明确地告诉编译器不要展开循环,因为外部循环非常短并且开销不值得。 在优化器处于最大设置状态时,通常唯一的方法是了解正在进行的操作是查看汇编列表,进行一些更改,然后再试一次。 在另一种情况下,我小心地展开了一个循环,因此编译器将使用AVX寄存器。 手动展开可能是必要的,因为编译器没有足够的关于循环长度的信息或者长度是特定倍数。 不幸的是,内部循环正在访问每组长度为4的浮点数的未对齐数组(16字节对齐)。 编译器仅使用传统的128位XMM寄存器。 在使用AVX内在函数进行向量化的弱尝试之后,我发现未对齐访问的额外开销使得性能不比gcc正在做的更好。 所以我想,我可以在缓存行的开头对齐每组浮点数,并使用等于缓存长度(或一半,即AVX寄存器的长度)的步幅来消除对齐问题。 但是,由于额外的内存带宽,这可能会变得无效。 这对我来说肯定更有意义。 它使代码更难理解。 并且,至少,正确的步伐将取决于我需要提供的编译时间常数。 我想知道是否有一些更简单的方法可以依靠编译器完成所有工作呢? 我愿意尝试它,如果它只意味着改变一行或两行代码。 如果我必须手动完成它(在这种情况下无论如何),这是不值得的。 (在我写这篇文章的过程中考虑它,我可以使用带有48个字节填充的联合或结构以及一些额外的代码行。我不得不考虑一下……)

放置在静态库中时找不到_sbrk函数

我正在为stm32f407微控制器创建一个裸机应用程序,该应用程序具有ARM Cortex M4内核。 因此,我正在自己提供像_sbrk这样的函数的实现。 我现在发现,当我尝试创建一个包含_sbrk的静态库,并将它与我的main.c链接到一个应用程序时,链接器说 “C:/progra~2/gnutoo~1/4947e~1.920/bin /../ LIB / GCC /臂-NONE-EABI / 4.9.3 /../../../../臂无-eabi / lib / armv7e -m / softfp \ libg_nano.a(lib_a-sbrkr.o):在函数_sbrk_r:sbrkr.c :(。text._sbrk_r + 0xc):未定义引用`_sbrk’“。 如果我从静态库中取出相同的函数,并将其放入main.c ,那么所有编译/链接/运行都很好。 我几乎可以肯定这与链接器在所有库中读取的顺序有关,并且当我自己的静态库被读取时, _sbrk需要_sbrk定义,因此被抛出,只是为了找到它无论如何,当后面的一个标准库被链接时,它是必需的。但是,我自己没有指定任何标准库,因此不能改变链接这些库的顺序。 我还尝试将_sbrk函数声明为__attribute __ ((__ used__ )) ,认为链接器不会丢弃该函数,但唉,这还没有解决我的问题。 所以我的问题是,如何将_sbrk放入静态库中,而不会_sbrk未解析的引用? 更新:链接最终应用程序的命令是: C:\ PROGRA~2 \ GNUTOO~1 \ 4947E~1.920 \ bin \ AR10B2~1.EXE -g -mcpu = cortex-m4 -mfpu = fpv4-sp-d16 […]

预处理器宏将hex字符串转换为字节数组

我在我的IDE中定义了一个AES-128密钥作为构建符号,因此它像这样调用GCC: arm-none-eabi-gcc -D”AES_KEY=3B7116E69E222295163FF1CAA1681FAC” … (相当于#define AES_KEY 3B7116E69E222295163FF1CAA1681FAC ) 优点是相同的符号也可以作为参数自动传递给构建后的CLI脚本,该脚本使用此密钥加密编译的代码(例如,用于安全的固件更新)… 但是如何在代码中将此键存储为字节数组? 我想定义一个执行转换的预处理器宏: uint8_t aes_key[] = { SPLIT_MACRO(AES_KEY) }; 至 uint8_t aes_key[] = {0x3B, 0x71, 0x16, 0xE6, 0x9E, 0x22, 0x22, 0x95, …}; 换句话说,GCC预处理器是否可以在2-char块中拆分密钥字符串并在它们之间添加“ , 0x ”?

gcc -ffp-contract选项的差异

我对GNU GCC中的-ffp-contract标志有疑问(参见https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html )。 标志文档编写如下: -ffp-contract=off禁用浮点表达式收缩。 -ffp-contract=fast启用浮点表达式收缩,例如,如果目标具有对它们的本机支持,则形成融合乘法 – 加法运算。 -ffp-contract=on如果语言标准允许,则启用浮点表达式收缩。 目前尚未实施和处理等于-ffp-contract=off 。 默认值为-ffp-contract=fast 。 现在的问题是: 快速和开启有什么区别? FMA旁边是否还有其他收缩示例(或类似于融合多子类)?

是C文件中需要extern“C”? (解决奇怪的Eclipse行为)

我对使用gcc和g ++工具的Mixed C / C ++应用程序比较陌生。 为了掌握它,我已经下载了iperf源代码并使用Eclipse成功构建了它。 有一个奇怪之处:如果我使用Eclipse查看文件“Thread.c”,它认为存在语法错误并且几乎整个文件都加下划线,好像代码有缺陷,这绝对不是。 这是触发它的代码片段: #ifdef __cplusplus extern “C” { #endif 我知道在C ++中使用extern“C”,但是当存在于.c文件中时Eclipse出现问题。 它很高兴地在.cpp和.h文件中接受它。 我已经检查了Make实用程序如何构建iperf应用程序,我看到它总是使用gcc来编译c文件和g ++来编译cpp文件,这让我想知道是否真的需要extern“C”。 它肯定没有受到伤害,因为gcc编译器很乐意处理它,但如果不是严格要求我可以省略它并在Eclipse中获得更好的可读性。 我还看了一个Eclipse的行为的可能解决方案,但还没有找到一个,如果有人能指出如何解决它同样好。

在ac程序中表达式是否太长可以编译gcc?

假设我将一个非常长的等式输入到一行c代码(.c或.h文件)中,该代码长度为数千(可能是数万)个字符; 例如 y = (2*(36*pow(x,2)*pow(A[n][j],5)*B[n][j] + (several thousand more such expressions) ) ; (这里只是将x作为变量,A,B作为双指针等)。 在gcc编译器无法正确编译代码之前,是否有一行代码在.c或.h文件中有多长时间? 我已经为#c阅读了几个关于这个问题的相关讨论,但不仅仅是简单的c。 我从来没有从gcc中收到任何关于我的代码中包含太长行的错误,但我想更加确定这一点。 编辑:在回应下面的一些评论时,我现在意识到我问了两个(我认为密切相关的)问题: (1)在gcc编译器可能发生错误/引发错误之前,行中c可以有多长时间有限制吗? (2)在gcc编译器可能发生错误/引发错误之前,表达式的复杂程度是否有限制? (例如,我们可以将很长的一行分成几行,但它们都是同一个表达式的一部分)。

将转到标签暴露给符号表

我想知道是否可以将函数中的goto标签暴露给C / C ++中的符号表 例如,我想从符号表中生成以下代码段的ret标签,并且可以使用标准API(如dlsym())进行引用。 感谢您的帮助! #include int main () { void *ret_p = &&ret; printf(“ret: %p\n”, ret_p); goto *ret_p; return 1; ret: return 0; }