Ошибка линковщика в непонятном месте, кто-то сталкивался?

Arhat109-2
Offline
Зарегистрирован: 24.09.2015
/tmp/build2401421066527260655.tmp/Arhat/arhat.c.o: In function `__vector_23':
/home/arhat109/Arduino/libraries/Arhat/arhat.h:601:(.text.__vector_23+0x3a): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
/home/arhat109/Arduino/libraries/Arhat/arhat.h:601:(.text.__vector_23+0x42): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
collect2: error: ld returned 1 exit status

Погуглил. Типа ситуация когда линкер не может переместить код из-за использованных относительных коротких переходов. ?!? как это?

Дело в том, что он указывает на .. точку входа в обработчик прерывания от таймера (__vector_23) .. Компиляция и сборка под ИДЕ 1.6.4, плата Ардуино Мега. Установки с тех пор "как инсталлировалась ИДЕ", так линкеру и не менялись..

То есть, выходит что компилятор не может передать управление на точку входа из таблицы векторов относительным переходом RJMP / RCALL?!?

Кто-то может пояснить в чем дело?

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

P.S.
 Потребовалось использовать хук для вызова процедур без параметров из под прерывания от таймера и тут-то и обнаружилось, что такой вызов "портит" несохраненные регистры. Добавил в обработчик сохранение и восстановление контекста и получил эту ошибку...

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Опции с которыми ИДЕ запускает компилятор:

~/progs/arduino-1.6.4/hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -MMD -mmcu=atmega2560 -DF_CPU=16000000L -DARDUINO=10604 -DARDUINO_AVR_MEGA2560 -DARDUINO_ARCH_AVR -I~/progs/arduino-1.6.4/hardware/arduino/avr/cores/arduino -I~/progs/arduino-1.6.4/hardware/arduino/avr/variants/mega -I~/Arduino/libraries/Arhat -I~/progs/arduino-1.6.4/hardware/arduino/avr/libraries/Wire -I~/Arduino/libraries/LiquidCrystal_I2C -I~/Arduino/libraries/Arhat/utility ~/Arduino/libraries/Arhat/arhat.c -o /tmp/build2401421066527260655.tmp/Arhat/arhat.c.o

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Теперь я ваще не понимаю в чем дело. Версия компилятора и линковщика 4.8.1 .. в которой опция предпочитать короткие относительные переходы (--) УДАЛЕНА вовсе!

"Update: To avoid the unnecessary confusion this error may cause -mshort-callswas deprecated in avr-gcc 4.7 and will be removed from 4.8. Source: GCC 4.8 Changes."

Что я сделал не так?

Клапауций 322
Offline
Зарегистрирован: 31.12.2015

скачай https://downloads.arduino.cc/arduino-1.6.8-windows.zip и попробуй всё заново.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

?!? вроде раз сто уже писал, что нет у меня батута, тьфу ты винды. У меня стоит (и это видно по тексту выше!) - рассовоправильный ЛИНУКС.

Да и вопрос вроде как не про какую-то сборку .. а в каких случаях такая ошибка может вылезти в "казалось бы" верном коде .. тем более, что опция линкера, её создающая - УДАЛЕНА из этой версии линковщика..

.. тут скорее всего какой-то косяк в коде или чем ещё... но вот с какой стороны копать - пока не доперло. Сталкивался? Когда, как .. адреса, пароли явки. Вдруг поможет...

Клапауций 322
Offline
Зарегистрирован: 31.12.2015

Arhat109-2 пишет:

?!? вроде раз сто уже писал, что нет у меня батута, тьфу ты винды. У меня стоит (и это видно по тексту выше!) - рассовоправильный ЛИНУКС.

мне плевать под чем ты сидишь: под виндой или под спайсами - скачай последню версию ИДЕ. начиная с версии 1.6.7 они многое исправили.

Arhat109-2 пишет:

в каких случаях такая ошибка может вылезти в "казалось бы" верном коде

в случае, если используешь гавно мамонта, а не последнюю финальную версию ИДЕ.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Ха, нашел!

Меня заинтриговала тестовка ошибки: .text.__vector_23+0x42 .. типа 42 байт от начала обработчика. Скомпилял в ассемблер и пошукал .. и упс, вот оно!

Код обработчика:

/**
 * Timer interrupt by Overflow Flag up each (TIMER_TICK_MCS*TIMER_MAX_COUNT) microseconds.
 *
 * Пользуемся побайтовой арифметикой: считали - добавили - сохранили.
 * Экономим регистры и команды:
 * "С" verison   = 158 bytes;
 * "ASM" version = 102 bytes, 46/51/75 cycles: 2.875mcsec for timer0_hook=0 and 4.6875 mcsec for empty call
 *
 * ISR(ISRtimer(TIME_DEFAULT, TIME_ISR), ISR_NAKED)
 *
 * equal this:
 *
 * void __vector_ 23(void) __attribute__ ((signal, used, externally_visible)) __attribute__((naked));
 * void __vector_ 23(void)
 */
ISR(ISRtimer(TIME_DEFAULT, TIME_ISR), ISR_NAKED)
//ISR(ISRtimer(TIME_DEFAULT, TIME_ISR))
{
/* C version:
 *
    timer0_overflow_count++;
    if( timer0_hook && !timer0_hook_run ){
        timer0_hook_run = 1;
        sei();
        timer0_hook();
        cli();
        timer0_hook_run = 0;
    }
*/
  asm volatile(
    "    push r30               \n\t"
    "    push r31               \n\t"
    "    in r30,__SREG__        \n\t"
    "    push r30               \n\t"

    "    lds r30,timer0_overflow_count   \n\t"
    "    lds r31,timer0_overflow_count+1 \n\t"
    "    adiw r30,1                      \n\t"
    "    sts timer0_overflow_count,r30   \n\t"
    "    sts timer0_overflow_count+1,r31 \n\t"
    "    clr r31                         \n\t"
    "    lds r30,timer0_overflow_count+2 \n\t"
    "    adc r30,r31                     \n\t"
    "    sts timer0_overflow_count+2,r30 \n\t"
    "    lds r30,timer0_overflow_count+3 \n\t"
    "    adc r30,r31                     \n\t"
    "    sts timer0_overflow_count+3,r30 \n\t"

    "    lds r30,timer0_hook                 ; if( timer0_hook && !timer0_hook_run ){\n\t"
    "    lds r31,timer0_hook+1                                                       \n\t"
    "    or  r30,r31                         ; (LByte | HByte) == 0?                 \n\t"
    "    breq .L1                                                                    \n\t"
    "    lds r30,timer0_hook_run                                                     \n\t"
    "    tst r30                             ; r30 & r30 != 0?                       \n\t"
    "    brne .L1                                                                    \n\t"

    "    inc r30                             ; timer0_hook_run = 1; \n\t"
    "    sts timer0_hook_run,r30                                    \n\t"

	"    push r0               \n\t"
	"    push r1               \n\t"
	"    push r2               \n\t"
	"    push r3               \n\t"
	"    push r4               \n\t"
	"    push r5               \n\t"
	"    push r6               \n\t"
	"    push r7               \n\t"
	"    push r8               \n\t"
	"    push r9               \n\t"
	"    push r10               \n\t"
	"    push r11               \n\t"
	"    push r12               \n\t"
	"    push r13               \n\t"
	"    push r14               \n\t"
	"    push r15               \n\t"
	"    push r16               \n\t"
	"    push r17               \n\t"
	"    push r18               \n\t"
	"    push r19               \n\t"
	"    push r20               \n\t"
	"    push r21               \n\t"
	"    push r22               \n\t"
	"    push r23               \n\t"
	"    push r24               \n\t"
	"    push r25               \n\t"
	"    push r26               \n\t"
	"    push r27               \n\t"
	"    push r28               \n\t"
	"    push r29               \n\t"

    "    lds r30,timer0_hook                 ; timer0_hook();       \n\t"
    "    lds r31,timer0_hook+1                                      \n\t"
    "    sei                                                        \n\t"
    "    icall                                                      \n\t"
    "    cli                                                        \n\t"

	"    pop r0           \n\t"
	"    pop r1           \n\t"
	"    pop r2           \n\t"
	"    pop r3           \n\t"
	"    pop r4           \n\t"
	"    pop r5           \n\t"
	"    pop r6           \n\t"
	"    pop r7           \n\t"
	"    pop r8           \n\t"
	"    pop r9           \n\t"
	"    pop r10           \n\t"
	"    pop r11           \n\t"
	"    pop r12           \n\t"
	"    pop r13           \n\t"
	"    pop r14           \n\t"
	"    pop r15           \n\t"
	"    pop r16           \n\t"
	"    pop r17           \n\t"
	"    pop r18           \n\t"
	"    pop r19           \n\t"
	"    pop r20           \n\t"
	"    pop r21           \n\t"
	"    pop r22           \n\t"
	"    pop r23           \n\t"
	"    pop r24           \n\t"
	"    pop r25           \n\t"
	"    pop r26           \n\t"
	"    pop r27           \n\t"
	"    pop r28           \n\t"
	"    pop r29           \n\t"

    "    clr r31                                                    \n\t"
    "    sts timer0_hook_run,r31             ; timer0_hook_run = 0; \n\t"

    ".L1:                  \n\t"
    "    pop r30           \n\t"
    "    out __SREG__,r30  \n\t"
    "    pop r31           \n\t"
    "    pop r30           \n\t"
    "    reti              \n\t"
    ::
  );

}

Отличие от репозиторного в том, что для сохранения контексту добавил команды push/pop на весь регистровый файл .. и смещения 0x3a, 0x42 - это как раз переходы на метку .L1

то бишь он не смог сгенерить адрес перехода из-за большого числа команд push/pop и "версия кумпилятора" тут ни при чем.

Решено, можно закрыть тему.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Одно не понял почему регистры пушатся в одном порядке, а обратно в другом, это кто так сделал? Выглядит жутковато :)

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Это я - тормоз .. спать уже сильно хотелось, уже исправлено конечно же. :)

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Так, все заработало как надо. Итого теперь имеем:

а) вариант короткого обработчика, без Хука вовсе: позволяет шустро и компактно считать время, не отвлекаясь если не требуется;

б) вариант с хуком, но без контекста сохранения (push/pop) .. не проверял, но похоже что если у процедур хука требовать выставление атрибута signal или volatile, то полное сохранение регистров будет им прописано компилятором автоматом .. надо попгобовать. Но тогда каждой, что не есть рассово-верно..

в) вариант с хуком И контекстом сохранения - для целей RTOS он получается самый компактный, даже в случае единственной процедуры хука. И, при таком указании места сохранения/восстановления контекста, в случае отсутствия процедуры или срабатывании защелки имеет наикратчайшее время исполнения самого обработчика. Удаление из описания обработчика NAKED - приведет к появлению глобального контекста сохранения, что негативно скажется на обработке прерывания независимо от режимов: есть проведура хука или нет ее, вызвана уже или ещё нет..

Хочется сохранить возможность компиляций по варианту "а" .. опять вводить "режим компиляции" константами препроцессора?

Да, и кстати, тут подумалось: а что если типовой процедуре из wiring.c просто устанавливать атрибу weak .. кумпилятыр перестанет матерится на два определения обработчиков? Может тогда будет и не надо выносить wiring.c? Да и для построения библиотек можно будет в целом рекомендовать такой подход .. интересно сочетание used и weak компилятор верно распознает что "втыкать обязательно, но не настырно"?