Computing > Embedded Computing

This is an armclang bug, isn't it? [It wasn't]

(1/1)

emece67:
Hi,

I do have a struct (inside a class pin_) with 5 members, 1 byte each, something like:

--- Code: ---struct pin_::conf_t {
  enum mode_t : uint8_t {
    GP_IN = 0,
    GP_OUT,
    ALTERNATE,
    ANALOG
  };

  enum type_t : uint8_t {
    PUSH_PULL = 0,
    OPEN_DRAIN
  };

  enum speed_t : uint8_t {
    LOW_SPEED = 0,
    MEDIUM_SPEED,
    HIGH_SPEED,
    VERY_HIGH_SPEED
  };

  enum pull_t : uint8_t {
    PULL_NONE = 0,
    PULL_UP,
    PULL_DOWN
  };

  enum function_t : uint8_t {
    AF0 = 0, AF1, AF2, AF3, AF4, AF5, AF6, AF7,
    AF8, AF9, AF10, AF11, AF12, AF13, AF14, AF15
  };

  mode_t      mode;
  type_t      type;
  speed_t     speed;
  pull_t      pull;
  function_t  function;
};
--- End code ---

Then I do have a method in class pin_ that takes one of such structs and configures the corresponding pin_:

--- Code: ---void pin_::configure(conf_t const& conf) const;
--- End code ---

Then I call such method with a literal parameter:

--- Code: ---    configure({
      .mode     = conf_t::GP_OUT,
      .type     = conf_t::PUSH_PULL,
      .speed    = conf_t::LOW_SPEED,
      .pull     = conf_t::PULL_NONE,
      .function = conf_t::AF0
    });
--- End code ---
and I get a HardFault.

The reason of the HardFault is that the compiled code that sets the parameters for the method call:

generates a STR r0, [sp, #0x29] instruction that, being the offset odd, tries an unaligned memory access.

This only happens when all 5 bytes of the struct evaluate to 0. To fix this I changed the length of the 1st member of the struct from uint8_t to uint32_t.

It's me or this is definitely a compiler bug?

Regards.

NOTE: armclang is the 6.16 version that comes with Keil 5.34



ataradov:
I'd say this is a bug. I see nothing wrong with this code.

Does it do the same if instead of a literal parameter you create a structure on the stack and pass that?

emece67:
Doing this:

--- Code: ---    conf_t  conf;

    conf.mode     = conf_t::GP_OUT;
    conf.type     = conf_t::PUSH_PULL;
    conf.speed    = conf_t::LOW_SPEED;
    conf.pull     = conf_t::PULL_NONE;
    conf.function = conf_t::AF0;

    configure(conf);
--- End code ---
shows the same behaviour. BUT, if the 1st member of the struct to be initialized happens not to be conf.mode, say:

--- Code: ---    conf_t  conf;

    conf.function = conf_t::AF0;
    conf.mode     = conf_t::GP_OUT;
    conf.type     = conf_t::PUSH_PULL;
    conf.speed    = conf_t::LOW_SPEED;
    conf.pull     = conf_t::PULL_NONE;

    configure(conf);
--- End code ---
then it works.

ataradov:
What MCU/core you are targeting?

According to this https://www.keil.com/support/man/docs/armclang_ref/armclang_ref_sam1444138667173.htm:

--- Quote ----munaligned-access is the default for architectures that support unaligned accesses to data. This default applies to all architectures supported by Arm Compiler 6, except Armv6‑M, and Armv8‑M without the Main Extension.

--- End quote ---

So if you are targeting Cortex-M4/M7, then it will default to unaligned access, so it has to be enabled in the core. Or pass -mno-unaligned-access flag.

emece67:

--- Quote from: ataradov on August 27, 2021, 08:19:14 pm ---What MCU/core you are targeting?


--- Quote ----munaligned-access is the default for architectures that support unaligned accesses to data. This default applies to all architectures supported by Arm Compiler 6, except Armv6‑M, and Armv8‑M without the Main Extension.

--- End quote ---

So if you are targeting Cortex-M4/M7, then it will default to unaligned access, so it has to be enabled in the core. Or pass -mno-unaligned-access flag.

--- End quote ---

That's it!

It is an stm32l432kc, with an M4 and, thus, supporting unaligned accesses. In any case a few days back I actively disabled unaligned access in the SCB   |O

Navigation

[0] Message Index

There was an error while thanking
Thanking...
Go to full version