реклама на сайте
подробности

 
 
> Указатель на функцию в компиляторе WINAVR
Giekelberri
сообщение Feb 16 2011, 12:18
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 18
Регистрация: 28-01-11
Пользователь №: 62 532



Всем привет!

Не могу понять работу компилятора WINAVR. Есть самый простейший код на С. В функции main() создается указатель на функцию evaluate(). Далее происходит вызов функции используя этот указатель.

Код
void evaluate(void)
{
}
int main(void)
{
    void (*p)(void) = evaluate;
    (*p)();
    return 0;
}


Однако, просмотрев сгенерированный ассемблерный код, получаю следующее (оптимизация отключена, не относящиеся к делу строки удалены):

Код
[b]000000be[/b] <evaluate>:
void evaluate(void)
{
  be:    df 93           push    r29
  c0:    cf 93           push    r28
  c2:    cd b7           in    r28, 0x3d; 61
  c4:    de b7           in    r29, 0x3e; 62
}
  c6:    cf 91           pop    r28
  c8:    df 91           pop    r29
  ca:    08 95           ret

000000cc <main>:
int main(void)
{
  cc:    df 93           push    r29
  ce:    cf 93           push    r28
  d0:    00 d0           rcall    .+0     ; 0xd2 <main+0x6>
  d2:    cd b7           in    r28, 0x3d; 61
  d4:    de b7           in    r29, 0x3e; 62
    void (*p)(void) = evaluate;
  d6:    8f e5           [b]ldi      r24, 0x5F[/b]; 95
  d8:    90 e0    [b]ldi      r25, 0x00[/b]; 0
  da:    9a 83           std    Y+2, r25; 0x02
  dc:    89 83           std    Y+1, r24; 0x01
    (*p)();
  de:    e9 81           ldd    r30, Y+1; 0x01
  e0:    fa 81           ldd    r31, Y+2; 0x02
  e2:    09 95           [b]icall[/b]
    return 0;
  e4:    80 e0           ldi    r24, 0x00; 0
  e6:    90 e0           ldi    r25, 0x00; 0
}
  e8:    0f 90           pop    r0
  ea:    0f 90           pop    r0
  ec:    cf 91           pop    r28
  ee:    df 91           pop    r29
  f0:    08 95           ret


Как видно, указатель на функцию evaluate() инициализируется значением r24:r25 = 5F00. Но почему? Ведь адрес функции evaluate() равен 000000be.

Сообщение отредактировал Giekelberri - Feb 16 2011, 12:21
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 6)
_Pasha
сообщение Feb 16 2011, 12:23
Сообщение #2


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(Giekelberri @ Feb 16 2011, 16:18) *
Как видно, указатель на функцию evaluate() инициализируется значением r24:r25 = 5F00. Но почему? Ведь адрес функции evaluate() равен 000000be.

Вы уж определитесь с нотацией хексов.
0x005F == 0x00be / 2

Go to the top of the page
 
+Quote Post
Giekelberri
сообщение Feb 16 2011, 12:36
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 18
Регистрация: 28-01-11
Пользователь №: 62 532



Тогда непонятно почему при простом ("обычном") вызове функции
Код
evaluate();

компилятор преобразовывает в ассемблерную инструкцию
Код
d4:    0e 94 5f 00     call    0xbe; 0xbe <evaluate>

,а при вызове функции через указатель на функцию в ассемблерную инструкцию
Код
  e2:    09 95          icall

, где в регистре Z находиться значение как вы написали
0x005F == 0x00be / 2

Go to the top of the page
 
+Quote Post
_Pasha
сообщение Feb 16 2011, 12:42
Сообщение #4


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Это половые трудности формата *.lss - файла.
Код
d4:    0e 94 5f 00
5f 00 - ничего не напоминает? sm.gif
Go to the top of the page
 
+Quote Post
Giekelberri
сообщение Feb 16 2011, 13:22
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 18
Регистрация: 28-01-11
Пользователь №: 62 532



Напоминает.
0e 94 5f 00 - Opcode инструкции CALL, где
параметр k, загружаемый в счетчик PC равен 00 5f

Flash память программ в AVR организована, как 32K/64K/128K x 16 разрядов (из документации). Так как большинство инструкций 16 разрядные.
icall - 16-разрядная (значение адреса функции находиться в Z-регистре)
call - 32-разрядная (значение адреса функции находиться в самом opcode)

получается, что "железная" адресация идет по 16 разрядов: 0, 1, 2, 3, 4, 5, ...
а в файле *.lss адресация идет по 8 разрядов: 0, 2, 4, 6, 8, 10, ...
но с шагом 2, в итоге получается те же 16 разрядов.

Провел дизассемблирование hex-файла


Для случая:
evaluate()
ассемблерный код
Код
+0000006A:   940E005F    CALL      0x0000005F     Call subroutine



Для случая:
void (*p)(void) = evaluate;
(*p)();
ассемблерный код
Код
+0000006B:   E58F        LDI       R24,0x5F       Load immediate
+0000006C:   E090        LDI       R25,0x00       Load immediate
+0000006D:   839A        STD       Y+2,R25        Store indirect with displacement
+0000006E:   8389        STD       Y+1,R24        Store indirect with displacement
+0000006F:   81E9        LDD       R30,Y+1        Load indirect with displacement
+00000070:   81FA        LDD       R31,Y+2        Load indirect with displacement
+00000071:   9509        ICALL                    Indirect call to (Z)



результат идентичен, без неявных делений на 2 в голове программиста...

Спасибо!
Go to the top of the page
 
+Quote Post
Skaf
сообщение Mar 2 2011, 15:24
Сообщение #6


Местный
***

Группа: Участник
Сообщений: 228
Регистрация: 4-06-09
Пользователь №: 49 940



У меня ссылки на функции сделаны так:

Код
unsigned char (*myTWI_Error)(unsigned char);
myTWI_Error = Func; //// unsigned char (*Func)(unsigned char)


Вызов так
Код
AnswerCode = (*myTWI_Error)(myTWI_Status);


Все работает
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Mar 2 2011, 19:02
Сообщение #7


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Цитата(Skaf @ Mar 2 2011, 18:24) *
У меня ссылки на функции сделаны так:


А можно и так:

Код
AnswerCode = myTWI_Error(myTWI_Status);
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 02:33
Рейтинг@Mail.ru


Страница сгенерированна за 0.01382 секунд с 7
ELECTRONIX ©2004-2016