Skip to content

initVariant() function not being linked in 1.6.6 #72

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ffissore opened this issue Nov 23, 2015 · 13 comments
Closed

initVariant() function not being linked in 1.6.6 #72

ffissore opened this issue Nov 23, 2015 · 13 comments
Assignees
Milestone

Comments

@ffissore
Copy link
Contributor

From @kmclifton on November 23, 2015 3:5

We have some custom init code that needs to run to initialise our hardware (not Arduino). In version 1.6.5 of the IDE we simply included a file called initvariant.cpp (defining void initVariant() ) alongside pins_arduino.h under variants/standard in our package directory. See contents of initvariant.cpp below. With the upgrade to 1.6.6 that seems to have broken. The init code no longer runs at all. It isn't linked in.
Possibly related to this issue: aee32ff

#include <Wire.h>
#include <Arduino.h>
#include <pins_arduino.h>

void initVariant() 
{ 
    Wire.begin();
    pinMode(EXPANDER_RSTN, OUTPUT);
    digitalWrite(EXPANDER_RSTN, LOW);
    delay(10);
    digitalWrite(EXPANDER_RSTN, HIGH);

    delay(10);
}

Copied from original issue: arduino/Arduino#4205

@ffissore
Copy link
Contributor Author

@kmclifton When I compile it I get

/tmp/arduino_a5e387bb8d8dac73c8f4a56a09b8171a/sketch_nov23a.ino: In function 'void initVariant()':
sketch_nov23a:8: error: 'EXPANDER_RSTN' was not declared in this scope
     pinMode(EXPANDER_RSTN, OUTPUT);
             ^

Is there some missing piece? Core, libs...?

@ffissore ffissore self-assigned this Nov 23, 2015
@kmclifton
Copy link

Apologies, @ffissore. Yes, there is a missing piece. We have the following definition in our pins_arduino.h file (located in variants/standard in the installed package directory).

static const uint8_t EXPANDER_RSTN = 6;

@kmclifton
Copy link

@ffissore Some more clues after experimenting a bit:

One difference between 1.6.5 and 1.6.6 relates to the command that generates the elf file.

The comparison:

1.6.5
C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-gcc -w -Os -Wl,--gc-sections -mmcu=atmega328p -o C:\Users\AppData\Local\Temp\build7760252863079702224.tmp/sketch_nov24a.cpp.elf C:\Users\AppData\Local\Temp\build7760252863079702224.tmp\sketch_nov24a.cpp.o C:\Users\AppData\Local\Temp\build7760252863079702224.tmp\initvariant.cpp.o C:\Users\AppData\Local\Temp\build7760252863079702224.tmp/core.a -LC:\Users\AppData\Local\Temp\build7760252863079702224.tmp -lm

1.6.6
"C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-gcc" -w -Os -Wl,--gc-sections -mmcu=atmega328p -o "C:\Users\AppData\Local\Temp\build11ee33954a5ebb625d1463b873c77548.tmp/sketch_nov24a.ino.elf" "C:\Users\AppData\Local\Temp\build11ee33954a5ebb625d1463b873c77548.tmp\sketch\sketch_nov24a.ino.cpp.o" "C:\Users\AppData\Local\Temp\build11ee33954a5ebb625d1463b873c77548.tmp/core\core.a" "-LC:\Users\AppData\Local\Temp\build11ee33954a5ebb625d1463b873c77548.tmp" -lm

Note how in 1.6.5, initvariant.cpp.o is included, but it's not there in 1.6.6.

Using 1.6.6 - if I add initvariant.cpp explicitly to the sketch (Sketch | Add File), then when I compile, it's listed in the command that generates the elf file, and we're back to working again.

@ffissore
Copy link
Contributor Author

Please provide the actual sketch, core and libs and error message you're getting: I can't reproduce your issue.
What I've attempted to do is:

Everything compiles as expected. Maybe a bug we've already solved in hourly builds? http://www.arduino.cc/en/Main/Software#hourly

@kmclifton
Copy link

Package at link below, including core etc. Library referenced in sketch also at link.
https://drive.google.com/folderview?id=0B1zBLRlluQd3eGFLZTNxSVdVdGs&usp=sharing
There is no error. The sketch compiles and uploads, but our initVariant() function doesn't get linked in. A snippet of the .lst file below shows that the initVariant() function that does get linked in is the default empty function:

 56a:        61 e0               ldi        r22, 0x01        ; 1
 56c:        8a e0               ldi        r24, 0x0A        ; 10
 56e:        0c 94 32 03         jmp        0x664        ; 0x664 <digitalWrite>

00000572 <initVariant>:
 572:        08 95               ret

00000574 <main>:
 574:        0e 94 f7 01         call        0x3ee        ; 0x3ee <init>
 578:        0e 94 b9 02         call        0x572        ; 0x572 <initVariant>
 57c:        0e 94 88 00         call        0x110        ; 0x110 <setup>

Sketch:

#include <dP_LedButton.h>

dP_LedButton myLedButton(2);

void setup() {
  myLedButton.begin();
}

void loop() {
  // TEST LED 1 (D1) and SWITCH 1 (SW1)
  if(myLedButton.readSwitch(1))
  {
    myLedButton.setLed(1, dP_LedButton::GREEN);
    delay(1000);    // 1 second delay
    myLedButton.setLed(1, dP_LedButton::RED);
    delay(1000);
    myLedButton.setLed(1, dP_LedButton::YELLOW);
    delay(1000);
    myLedButton.setLed(1, dP_LedButton::OFF);
    delay(1000);  
  }


}

@feilipu
Copy link

feilipu commented Nov 25, 2015

@matthijskooijman
Copy link
Collaborator

So the forum post suggests that calling a weak function from within the same compilation unit (cpp file) as where the empty weak stub is defined, causes problems. Presumably the compiler then inlines the function, or otherwise directly references it, without involving the linker, so the call will not use the other, strong, definition of the function. To fix this this, moving the weak empty initVariant into another cpp file (the forum post suggests hooks.cpp) would help.

I'm not 100% sure this analysis is correct, especially since the disassembler dump shows that no inlining takes place. I wonder if somehow the linking order, and/or .a archive linking affects which initVariant function is selected as well.

@feilipu
Copy link

feilipu commented Nov 25, 2015

To be honest, I'm not sure of the technical reason why this works.
I don't have a deep enough understanding of the vagaries of the gcc compiler and linker.

What I can say is that I spent hours on this issue, including moving the linker order and putting the external library before the ArduinoCore library, with no outcome. The .mpp file just showed the empty initVariant() function, not inlined.

Simply moving the attribute((weak)) function definitions to another file solved the problem.
And to be honest, putting all the empty hooks into the hooks.c file is a nicer solution anyway.

Still, it would be nice to know why this solution works.

@ffissore ffissore assigned cmaglie and unassigned ffissore Nov 25, 2015
@ffissore
Copy link
Contributor Author

Since the problem, atm, seems to lie in Arduino core files, I'm assigning this to @cmaglie /cc @facchinm . If you guys come up with a fix at arduino-builder level, like reordering linker params, pls reassign this to me

@ffissore ffissore assigned ffissore and unassigned cmaglie Nov 25, 2015
@ffissore ffissore added this to the 1.2.7 milestone Nov 25, 2015
@ffissore
Copy link
Contributor Author

Turned out the problem was in a wrong porting from java to go. Variant files were archived in core.a while they MUST be passed to the linker one by one

@ffissore
Copy link
Contributor Author

A fix is available with latest IDE hourly build http://www.arduino.cc/en/Main/Software#hourly

@kmclifton
Copy link

Thanks, @ffissore. That seems to have fixed things. I assume that this will then make it into 1.6.7?

@ffissore
Copy link
Contributor Author

ffissore commented Dec 2, 2015

Yes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants