Gcc Cortex-M编译器生成不正确的FOR循环

Gcc Cortex-M编译器生成不正确的FOR循环,gcc,arm,undefined-behavior,cortex-m,compiler-bug,Gcc,Arm,Undefined Behavior,Cortex M,Compiler Bug,在Cortex-M 4和Cortex-M 0上测试和复制。 我发现GCC编译器有一个问题。当一个函数被声明为int类型(非void),并且包含for循环,但没有return语句时,for循环不会中断;在反汇编代码之后,有返回和无返回的函数之间存在差异 编译此代码时,不会抛出错误消息。在第一次编译时,会抛出一个关于缺少return语句的警告,但在这之后,该警告将不会再次出现,直到您重新启动IDE。如此严重的问题可能无法编译,或者至少使Arduino崩溃,但它永远不会脱离for循环 我主要是想找到适

在Cortex-M 4和Cortex-M 0上测试和复制。

我发现GCC编译器有一个问题。当一个函数被声明为int类型(非void),并且包含for循环,但没有return语句时,for循环不会中断;在反汇编代码之后,有返回和无返回的函数之间存在差异

编译此代码时,不会抛出错误消息。在第一次编译时,会抛出一个关于缺少return语句的警告,但在这之后,该警告将不会再次出现,直到您重新启动IDE。如此严重的问题可能无法编译,或者至少使Arduino崩溃,但它永远不会脱离for循环

我主要是想找到适当的渠道来报告这一点,因为我不确定是否launchpad或是否继续维护。如果有人知道哪个站点(或两者)仍在维护中,或者如果有人直接与项目中的某个人联系,我可以与他分享,请分享

下面是对该行为更全面的描述

Arduino代码
=============
这是一个最小可复制示例的尝试。在较大的项目中,我曾在两个不同的场合遇到过这个问题,这会导致程序以非常意外和难以调试的方式运行(但总是通过在函数定义中添加return语句来修复)

int-affunctionnoreturn(int计数)
{
42f8:b538推动{r3,r4,r5,lr}
连续打印(“CountNR”);
42fa:4909 ldr r1,[pc,#36];(4320)
序列号.println(计数);

对于(int i=0;i也许能说的最有帮助的事情是:“为什么你想错过返回语句?你希望实现什么?”

各种语言标准(Arduino有点像C++但有一些有趣的预处理)告诉你如果你写了有效的代码会发生什么。他们并不总是告诉你如果你写了无效的代码会发生什么。在这种情况下,编译器已经非常有帮助地指出了你的代码错误的原因,但是在那之后,它完全可以自由地做任何事情。无论它做什么,这都不是编译器中的错误,而是代码中的错误。这它有时被称为“垃圾输入-垃圾输出”

为了解释为什么会得到这样的结果,可以这样想:编译器知道在一个有效的程序中,如果没有return语句,执行永远不会运行到函数的末尾,因此如果循环后没有return语句,可以安全地假设它永远不会离开循环优化有效代码以更快地运行。如果此假设改变了无效程序的功能,则编译器作者通常不关心。他们通常只关心有效程序的功能


(关于launchpad页面,如果您单击页面顶部的大链接,您将看到一条关于站点移动到何处的消息).

您使用的编译器选项是什么?
会抛出缺少的返回语句,但之后警告将不会再次出现,直到您重新启动IDE。
这与您的IDE有关。您是否能够使用更简单的代码重新创建行为,而不使用Arduino库?
在Cortex-M 4和Cortex-M 0上复制。
因此我们知道Cortex你在使用什么控制器?请提供更多信息。一个最小的可复制示例,gcc版本,命令行选项,摆脱库调用并用其他东西替换它们,等等。我还可以复制这个。请使用objdump-d而不是gdbit。很明显,工具链仍在维护中,当前版本,具有返回路径的生成。请提供一个可重复的、最小的示例。请三次检查代码是否实际编译且没有错误。
int-affunctionnoreturn()
应声明为
void-affunctionnoreturn()
相反,因为它不会返回任何内容。GCC错误通常取决于版本。我们最近使用较旧的7-2017-q4编译器进行了测试,它的功能与预期一致(没有功能流问题).当为标准Arduino Mega 2560编译代码时,代码也以这种方式运行,因此它仅限于Cortex M编译器。我们还测试了这两个函数:当调用FunctionNoForNoreturn(5)时,输出如下:CountNoForNR5 CountNoForWR0这里发生的是程序执行FunctionNoForNoreturn(),然后流入functionNoForWithReturn(),然后由于堆栈混乱而崩溃。
intaFunctionNoForNoreturn(int count){Serial.print(“CountNoForNR”);Serial.println(count);delay(1000);}intaFunctionNoForWithReturn(int count){Serial.print(“CountNoForWR”);Serial.println(count);delay(1000);return(count);})
它始终按预期运行。运行到下一个函数是预期的行为。崩溃是预期的行为。您的程序显示未定义的行为。这意味着您必须预期它可以做任何事情。即使它打印出“我是一条鱼”,上下跳跃并着火,这仍然是您应该期望的正确行为。尝试在谷歌搜索“未定义的行为”在C++中,如果调用方会使用返回值,函数只需要返回一个值。尽管现代风格有利于返回值,即使在不需要这样做时,在许多实现中,函数的结尾也会稍微快一些。空函数作为UB,用C和C++编写的函数集合混合使用,可以有效地处理函数的定义,其功能是用一种语言定义的,而不是用另一种语言定义的函数。
/*
  gcc compiler error demonstration for Adafruit GrandCentral 
  gcc version: gcc version 9.2.1 20191025 (release) [ARM/arm-9-branch revision 277599] (GNU Tools for Arm Embedded Processors 9-2019-q4-major)
  Arduino IDE: all warinings on 
  Arduino IDE version 1.8.13
  Adafruit SAMD version 1.8.11
  based on Blink
  
  modified to call two functions which are identical except one does not have a return
  statement even though it is of return type int.
  In the list file, myList.GrandCentral.lst ,AFunctionWithReturn shows both the comparison of
  i with Count and the conditional comparison i>7 with break assembly instructions
  The AFunctionNoReturn does not show any assembly instructions for the end of 
  loop comparision or the conditional comparison i>7 with break 

  Found 4/8/21 Robert Calay and Tristan Calay



  Turns an LED on for one second, then off for one second, repeatedly.

  Most Arduinos have an on-board LED you can control. On the UNO, MEGA and ZERO
  it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN is set to
  the correct LED pin independent of which board is used.
  If you want to know what pin the on-board LED is connected to on your Arduino
  model, check the Technical Specs of your board at:
  https://www.arduino.cc/en/Main/Products

  modified 8 May 2014
  by Scott Fitzgerald
  modified 2 Sep 2016
  by Arturo Guadalupi
  modified 8 Sep 2016
  by Colby Newman

  This example code is in the public domain.

  http://www.arduino.cc/en/Tutorial/Blink
*/
#define MAIN
//#include "Serial3.h" We are re-directing serial port output to SERCOM 5 on the Grand Central M4.

int AFunctionWithReturn(int count)
{
  Serial.print("CountWR");
  Serial.println(count);
  for(int i=0;i<count;i++) {
    Serial.println(i);
    if (i>7)
      break;
  }
 return(1); 
}

int AFunctionNoReturn(int count)
{
  Serial.print("CountNR");
  Serial.println(count);
  for(int i=0;i<count;i++) {
    Serial.println(i);
    if (i>7)
      break;
  }
 //Note: No return statement here.
}

// the setup function runs once when you press reset or power the board
void setup() {
  Serial.begin(115200);
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  AFunctionWithReturn(10); //This loops 8 times
  AFunctionNoReturn(10);   //This loops forever, never reaching loop()
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}


/*
 OUTPUT ON ADAFRUIT GRANDCENTRAL SERIAL PORT
CountWR10
0
1
2
3
4
5
6
7
8
CountNR10
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
DOES NOT STOP CONTINUES 2000000+
* 
* 
 */
int AFunctionWithReturn(int count)
{
    42bc:   b570        push    {r4, r5, r6, lr}
  Serial.print("CountWR");
    42be:   490c        ldr r1, [pc, #48]   ; (42f0 <_Z19AFunctionWithReturni+0x34>)
  Serial.println(count);
  for(int i=0;i<count;i++) {
    Serial.println(i);
    42c0:   4e0c        ldr r6, [pc, #48]   ; (42f4 <_Z19AFunctionWithReturni+0x38>)
{
    42c2:   4605        mov r5, r0
  Serial.print("CountWR");
    42c4:   480b        ldr r0, [pc, #44]   ; (42f4 <_Z19AFunctionWithReturni+0x38>)
    42c6:   f000 fafa   bl  48be <_ZN5Print5printEPKc>
  Serial.println(count);
    42ca:   480a        ldr r0, [pc, #40]   ; (42f4 <_Z19AFunctionWithReturni+0x38>)
    42cc:   220a        movs    r2, #10
    42ce:   4629        mov r1, r5
    42d0:   f000 fb43   bl  495a <_ZN5Print7printlnEii>
  for(int i=0;i<count;i++) {
    42d4:   2400        movs    r4, #0
    42d6:   42ac        cmp r4, r5
    42d8:   da08        bge.n   42ec <_Z19AFunctionWithReturni+0x30>
    Serial.println(i);
    42da:   220a        movs    r2, #10
    42dc:   4621        mov r1, r4
    42de:   4630        mov r0, r6
    42e0:   f000 fb3b   bl  495a <_ZN5Print7printlnEii>
    if (i>7)
    42e4:   2c08        cmp r4, #8
    42e6:   d001        beq.n   42ec <_Z19AFunctionWithReturni+0x30>
  for(int i=0;i<count;i++) {
    42e8:   3401        adds    r4, #1
    42ea:   e7f4        b.n 42d6 <_Z19AFunctionWithReturni+0x1a>
      break;
  }
 return(1); 
}
int AFunctionNoReturn(int count)
{
    42f8:   b538        push    {r3, r4, r5, lr}
  Serial.print("CountNR");
    42fa:   4909        ldr r1, [pc, #36]   ; (4320 <_Z17AFunctionNoReturni+0x28>)
  Serial.println(count);
  for(int i=0;i<count;i++) {
    Serial.println(i);
    42fc:   4d09        ldr r5, [pc, #36]   ; (4324 <_Z17AFunctionNoReturni+0x2c>)
{
    42fe:   4604        mov r4, r0
  Serial.print("CountNR");
    4300:   4808        ldr r0, [pc, #32]   ; (4324 <_Z17AFunctionNoReturni+0x2c>)
    4302:   f000 fadc   bl  48be <_ZN5Print5printEPKc>
  Serial.println(count);
    4306:   4621        mov r1, r4
    4308:   4806        ldr r0, [pc, #24]   ; (4324 <_Z17AFunctionNoReturni+0x2c>)
    430a:   220a        movs    r2, #10
    430c:   f000 fb25   bl  495a <_ZN5Print7printlnEii>
  for(int i=0;i<count;i++) {
    4310:   2400        movs    r4, #0
    Serial.println(i);
    4312:   4621        mov r1, r4
    4314:   220a        movs    r2, #10
    4316:   4628        mov r0, r5
    4318:   f000 fb1f   bl  495a <_ZN5Print7printlnEii>
  for(int i=0;i<count;i++) {
    431c:   3401        adds    r4, #1
    431e:   e7f8        b.n 4312 <_Z17AFunctionNoReturni+0x1a>
    4320:   00006538    .word   0x00006538
    4324:   2000011c    .word   0x2000011c

00004328 <loop>:
  AFunctionWithReturn(10);
  AFunctionNoReturn(10);
}