esp8266 / Arduino

ESP8266 core for Arduino
GNU Lesser General Public License v2.1
15.99k stars 13.33k forks source link

Assembler errors while compiling on esphome with framework version >=3.0.0 #8672

Closed Chupaka closed 2 years ago

Chupaka commented 2 years ago

Basic Infos

Platform

Problem Description

Hello. I came from ESPHome world, going deeper and deeper (ESPHome -> PlatformIO -> ESP8266 core for Arduino) trying to debug this problem.

This initially was published as ESPHome issue https://github.com/esphome/issues/issues/3311

When the code below is being built with framework version 3.0.0 or higher, the process fails with errors like this:

/tmp/ccHYx8E4.s: Assembler messages:
/tmp/ccHYx8E4.s: Warning: end of file in string; '"' inserted
/tmp/ccHYx8E4.s:31: Error: bad register name:   a2
/tmp/ccHYx8E4.s:31: Error: junk at end of line, first unrecognized character valued 0x9
/tmp/ccHYx8E4.s:32: Error: bad register name:   sp
/tmp/ccHYx8E4.s:32: Error: junk at end of line, first unrecognized character valued 0x9
/tmp/ccHYx8E4.s:33: Error: bad register name:   a2
/tmp/ccHYx8E4.s:33: Error: junk at end of line, first unrecognized character valued 0x9
/tmp/ccHYx8E4.s:34: Error: bad register name:   a0
/tmp/ccHYx8E4.s:34: Error: junk at end of line, first unrecognized character valued 0x9
/tmp/ccHYx8E4.s:35: Error: bad register name:   a3
<<< many lines of similar errors here >>>

If I switch back to version 2.7.4 (well, looks like for some reason PlatformIO uses 2.6.3 in that case), everything is fine, it builds successfully and works as expected.

MCVE Sketch

Minimal code for reproduction in ESPHome is https://gist.github.com/Chupaka/6679f559a29aa513bc4e8120762b2cdc (2 small files)

To get back to framework 2.7.4, edit t.yaml:

esp8266:
  board: d1_mini
  framework:
    version: 2.7.4
mcspr commented 2 years ago

What happens in command line? i.e. esphome equivalent of pio run --environment $env --jobs 1 --verbose Where does t.h go in the resulting source file? Are there any intermediate files, generated by esphome, which could be compiled manually to reproduce the issue? Does removing IRAM_ATTR help?

Chupaka commented 2 years ago

ESPHome successfully generates this build dir:

.
├── platformio.ini
├── post_build.py
└── src
    ├── esphome
    │   ├── components
    │   │   ├── custom_component
    │   │   │   └── custom_component.h
    │   │   ├── esp8266
    │   │   │   ├── core.cpp
    │   │   │   ├── core.h
    │   │   │   ├── gpio.cpp
    │   │   │   ├── gpio.h
    │   │   │   ├── preferences.cpp
    │   │   │   └── preferences.h
    │   │   └── preferences
    │   │       └── syncer.h
    │   └── core
    │       ├── application.cpp
    │       ├── application.h
    │       ├── automation.h
    │       ├── base_automation.h
    │       ├── color.cpp
    │       ├── color.h
    │       ├── component.cpp
    │       ├── component.h
    │       ├── component_iterator.cpp
    │       ├── component_iterator.h
    │       ├── controller.cpp
    │       ├── controller.h
    │       ├── datatypes.h
    │       ├── defines.h
    │       ├── entity_base.cpp
    │       ├── entity_base.h
    │       ├── gpio.h
    │       ├── hal.h
    │       ├── helpers.cpp
    │       ├── helpers.h
    │       ├── log.cpp
    │       ├── log.h
    │       ├── macros.h
    │       ├── optional.h
    │       ├── preferences.h
    │       ├── scheduler.cpp
    │       ├── scheduler.h
    │       ├── util.cpp
    │       ├── util.h
    │       └── version.h
    ├── esphome.h
    ├── main.cpp
    └── t.h

Here are the actual files: thermik.tar.gz

If I run platformio run -j1 -v in that dir - I get the error near here:

xtensa-lx106-elf-g++ -o .pio/build/thermik/src/main.cpp.o -c -fno-rtti -std=gnu++17 -fno-exceptions -Wno-nonnull-compare -Wno-sign-compare -Wno-unused-but-set-variable -Wno-unused-variable -fno-exceptions -Os -mlongcalls -mtext-section-literals -falign-functions=4 -U__STRICT_ANSI__ -D_GNU_SOURCE -ffunction-sections -fdata-sections -Wall -Werror=return-type -free -fipa-pta -DPLATFORMIO=60002 -DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_WEMOS_D1MINI -DNEW_OOM_ABORT -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH -DUSE_ARDUINO -DUSE_ESP8266 -DUSE_ESP8266_FRAMEWORK_ARDUINO -DF_CPU=80000000L -D__ets__ -DICACHE_FLASH -DARDUINO=10805 -DARDUINO_BOARD=\"PLATFORMIO_D1_MINI\" -DFLASHMODE_DOUT -DLWIP_OPEN_SRC -DNONOSDK22x_190703=1 -DTCP_MSS=1460 -DLWIP_FEATURES=0 -DLWIP_IPV6=0 -DVTABLES_IN_FLASH -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 -Isrc -I/Users/pavel.skuratovich/.platformio/packages/framework-arduinoespressif8266/tools/sdk/include -I/Users/pavel.skuratovich/.platformio/packages/framework-arduinoespressif8266/cores/esp8266 -I/Users/pavel.skuratovich/.platformio/packages/toolchain-xtensa/include -I/Users/pavel.skuratovich/.platformio/packages/framework-arduinoespressif8266/tools/sdk/lwip2/include -I/Users/pavel.skuratovich/.platformio/packages/framework-arduinoespressif8266/variants/d1_mini src/main.cpp
/var/folders/rx/t2c84qxj26xb4xcz964dhx3m0000gp/T//ccSbHKSK.s: Assembler messages:
/var/folders/rx/t2c84qxj26xb4xcz964dhx3m0000gp/T//ccSbHKSK.s: Warning: end of file in string; '"' inserted
/var/folders/rx/t2c84qxj26xb4xcz964dhx3m0000gp/T//ccSbHKSK.s:31: Error: bad register name:  a2
/var/folders/rx/t2c84qxj26xb4xcz964dhx3m0000gp/T//ccSbHKSK.s:31: Error: junk at end of line, first unrecognized character valued 0x9
/var/folders/rx/t2c84qxj26xb4xcz964dhx3m0000gp/T//ccSbHKSK.s:32: Error: bad register name:  sp
/var/folders/rx/t2c84qxj26xb4xcz964dhx3m0000gp/T//ccSbHKSK.s:32: Error: junk at end of line, first unrecognized character valued 0x9
/var/folders/rx/t2c84qxj26xb4xcz964dhx3m0000gp/T//ccSbHKSK.s:33: Error: bad register name:  a2
/var/folders/rx/t2c84qxj26xb4xcz964dhx3m0000gp/T//ccSbHKSK.s:33: Error: junk at end of line, first unrecognized character valued 0x9

But if I editplatformio.ini to change

platform = platformio/espressif8266 @ 3.2.0
platform_packages =
    platformio/framework-arduinoespressif8266 @ ~3.30002.0

to

platform = platformio/espressif8266 @ 2.6.3
platform_packages =
    platformio/framework-arduinoespressif8266 @ ~3.20704.0

then platformio run succeeds.

Chupaka commented 2 years ago

Does removing IRAM_ATTR help?

Yes

mcspr commented 2 years ago
--- src/t.h     2022-09-11 22:32:42.000000000 +0300
+++ src/t.h.mod 2022-09-11 23:05:37.294064517 +0300
@@ -15,10 +15,12 @@
     ((MyComponent*)OTC)->process();
   }

-  IRAM_ATTR void process() {
+  void process();
+};
+
+IRAM_ATTR void process() {
     const char* Peow[] = {
       "A",
       "B"
     };
-  }
-};
+}

(if someone more familiar with section <-> asm <-> inline decl and def interaction could explain this, please do :)

Chupaka commented 2 years ago

Wow, good job! And it even works with the same definition but external implementation (not sure if those terms are correct). Wonder if I should leave the first IRAM_ATTR in place...


  IRAM_ATTR void process();
};

IRAM_ATTR void MyComponent::process() {
  const char* Peow[] = {
    "A",
    "B"
  };
}

My main project works with the recommended framework now using this workaround. Thank you, @mcspr!

mcspr commented 2 years ago

Oops, sorry, that is what I meant. You could totally could use either standalone func or a class method, the point is just to move both section attribute and function body out of the class body aka make it not inline.

It does seem like a workaround, true, just not sure which part of the build takes the blame Closing this as the immediate issue is solved, perhaps we could come back to this later

jjsuwa-sys3175 commented 2 years ago

The true MCVE is here: It doesn't require any external environment, reproduces only with the toolchain. (cmdline: "xtensa-lx106-elf-g++ -std=gnu++17 -Os -fno-inline-functions -fno-exceptions -mlongcalls -mtext-section-literals -c")

struct foo {
  __attribute__((section ("\"bar.42\"")))
  void init() {
    const char* astr[] = { "A", "B" };
  }
  foo() {
    init();
  }
} x;

You might want to change "-c" to "-S" and see the assemble listing :) (imho this is a bug of GCC, not others)

mcspr commented 2 years ago

Something in optimization, then?

~/d/arduino8672> xtensa-lx106-elf-g++ -c -O0 mcve.cpp
~/d/arduino8672> xtensa-lx106-elf-g++ -c -O1 mcve.cpp
/tmp/cc90CD6F.s: Assembler messages:
/tmp/cc90CD6F.s: Warning: end of file in string; '"' inserted
/tmp/cc90CD6F.s:18: Warning: missing closing '"'
/tmp/cc90CD6F.s:18: Error: unknown opcode or format name ''

edit: ref. -S, this does not seem right

    .section    .rodata.42".str1.4,"aMS",@progbits,1 
mcspr commented 2 years ago

Looking a second time

-   __attribute__((section ("\"bar.42\"")))
+   __attribute__((section ("bar.42"))) 

This generates

    .section    .rodata.42.str1.4,"aMS",@progbits,1

Versus the faulty

    .section    .rodata.42".str1.4,"aMS",@progbits,1
jjsuwa-sys3175 commented 2 years ago

Looking a second time

-   __attribute__((section ("\"bar.42\"")))
+   __attribute__((section ("bar.42"))) 

This generates

    .section    .rodata.42.str1.4,"aMS",@progbits,1

Versus the faulty

    .section    .rodata.42".str1.4,"aMS",@progbits,1

One more thing: What does that ".section" qualify?

mcspr commented 2 years ago

One more thing: What does that ".section" qualify?

const char* array inside of the method

    .file   "mcve.cpp"
    .section    .rodata.42".str1.1,"aMS",@progbits,1 ; <<<
.LC0:
    .string "A"
.LC1:
    .string "B"
    .text
    .global x
    .section    .bss
    .type   x, @object
    .size   x, 1
x:
    .zero   1
    .ident  "GCC: (GNU) 10.3.0"
jjsuwa-sys3175 commented 2 years ago

One more thing: What does that ".section" qualify?

const char* array inside of the method

But we should have expected foo::init() rather than an array of const char*. How strange!

mcspr commented 2 years ago

One more thing: What does that ".section" qualify?

const char* array inside of the method

But we should have expected foo::init() rather than an array of const char*. How strange!

Which is inlined here, so supposedly it is generated at some point and then discarded?

My bet is off-by-one error, somewhere dealing with these section strings (if / when they are in nearby memory) :) BTW latest gcc8.4 xtensa build from espressif - https://github.com/espressif/crosstool-NG/releases - this does not seem to do this kind of thing. Maybe something broken in-between the versions.