Problem comping simple asm function by g++

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I try to compile a simple function for XMEGA256A3BU:

uint8_t NVM_read_byte(uint8_t cmd, uint16_t address)

{

       uint8_t result;

      

       asm volatile(

             "in r25, __SREG__" "\n\t" 

             "cli" "\n\t"

             "lds __tmp_reg__, %A3" "\n\t"   

             "sts %A3, %[cmd]" "\n\t"        

             "lpm %[result], Z" "\n\t"       

             "sts %A3, __tmp_reg__" "\n\t"   

             "out __SREG__, r25" "\n\t"

             : [result] "=r" (result)

             : [cmd] "r" (cmd), "z" (address), [nvm_cmd] "m" (NVM_CMD)

             : "r25"

       );

      

       return result;

}

When compiling using avr-gcc everything is ok, program compiles and executes fine. But the same code compiled by avr-g++ produces the following errors:

Error                     undefined reference to `X'

Errors are related to following instructions:

"lds __tmp_reg__, %A3" "\n\t"   

"sts %A3, %[cmd]" "\n\t"  

"sts %A3, __tmp_reg__" "\n\t"   

It seems that the error is produced only during compiling with g++, extern “c” doesn’t change the situation. Can any body help? Thanks in advance.

This topic has a solution.
Last Edited: Mon. May 20, 2019 - 04:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What's the purpose of A in op 3?
.
To check the code generated by the compiler proper use -save-temps and inspect the .s file.

avrfreaks does not support Opera. Profile inactive.

Last Edited: Sun. May 19, 2019 - 07:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

...

avrfreaks does not support Opera. Profile inactive.

Last Edited: Sun. May 19, 2019 - 07:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The obvious question is "why do you want to do that?" And the answer to that is also obvious, "because I want to."

 

Um, so what is this assembly operation intended to do?

If you don't know my whole story, keep your mouth shut.

If you know my whole story, you're an accomplice. Keep your mouth shut. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What makes you think the error relates to this sequence? The actual error is an undef ref so it seems its trying to locate a symbol X yet as far as I can see there's no mention of an X in the sequence given.

Last Edited: Sun. May 19, 2019 - 08:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

SprinterSB wrote:
What's the purpose of A in op 3?
.
To check the code generated by the compiler proper use -save-temps and inspect the .s file.

 

Sorry, my mistake. Of course there should be only %3 instead %A3.

But it didn’t solve my problem, still as result I have an error: Undefined reference to X. According to your suggestion, I inspected the temporary .s files. And here is the surprise. Compilation with –Os, generates the following code:

in r25, __SREG__

cli

lds __tmp_reg__, 458

sts 458, r24

lpm r24, Z

sts 458, __tmp_reg__

out __SREG__, r25

which compiles just fine. The problem is –O0 flag, which generates the following code:

in r25, __SREG__

cli

lds __tmp_reg__, X

sts X, r24

lpm r24, Z

sts X, __tmp_reg__

out __SREG__, r25

Obviously lds/sts with X will fail. Both gcc and g++ generates the same wrong code with –O0 flag. So temporary my problem is solved, as I’m interested in compiling with –Os, but is it a compilator fault, or I don’t know about something?

Thank you very much for your help. It saved me a lot of time.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
What makes you think the error relates to this sequence? The actual error is an undef ref so it seems its trying to locate a symbol X yet as far as I can see there's no mention of an X in the sequence given.

I’ve commented indicated assembler instructions, which prevented the error. That’s why I’m pretty sure about instructions which are the error source.

 

Torby wrote:

The obvious question is "why do you want to do that?" And the answer to that is also obvious, "because I want to."

 

Um, so what is this assembly operation intended to do?

The function reads a byte through NVM controller using cmd as NVM command. Results depends on selected NVM command.

Last Edited: Sun. May 19, 2019 - 08:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TFrancuz wrote:
Obviously lds/sts with X will fail. Both gcc and g++ generates the same wrong code with –O0 flag.
Then surely this about the invocation of the actual   NVM_read_byte(uint8_t cmd, uint16_t address) function so what is being passed in as "cmd" ?

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, the problem is the constraint "m" which allows any memory reference including indirect via X. Check the asm before the inline asm and you will find that the compiler loads 458 to X, and X is no valid addressing mode for LDS (it's interpreted as symbol "X" here) .
.
Try "i" as constraint: some value known at link-time or earlier, which is what LDS can encode. "n" will also work because NVM_CMD is obviously known at compile-time.

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

... bit more complicated. Use constraint "i" with &NVM_CMD (it's the address that's known, not the content of that memory location). That's it, because the content of memory does (effectively) not change in your special case.
.
If it would change then you'd add a generic clobber "memory" or an additional operand "=m" (NVM_CMD). Such operand would not be used in the asm template, it just indicates to gcc precisely what memory location is affected.

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

SprinterSB - thank you very much again!

„i” constraint works very well with every optimization level. I thought that “i” works only with IO space, that’s why I used “m”.