2012-03-22 4 views
4

Я пытаюсь отладить функцию Reset_Handler(), написанную на ассемблере (который я не понимаю, но был предоставлен как часть стандартной библиотеки). Используя GDB, я просматриваю каждую инструкцию, используя ni. Вот что я получаю:Счетчик программ, не продвигающийся

(gdb) ni 
0x08005dc4 in Reset_Handler() 
(gdb) ni 
0x08005dc6 in Reset_Handler() 
(gdb) ni 
0x08005dc6 in Reset_Handler() 
(gdb) ni 
0x08005dc6 in Reset_Handler() 
(gdb) ni 
0x08005dc6 in Reset_Handler() 

В действительности, указатель программа получает «застревают» на 0x08005dc6. Является ли это нормальным поведением, или должен ли указатель программы прогрессировать каждый раз, когда я делаю ni? Ниже начало Reset_Handler():

.section .text.Reset_Handler 
    .weak Reset_Handler 
    .type Reset_Handler, %function 
Reset_Handler: 

/* Copy the data segment initializers from flash to SRAM */ 
    movs r1, #0 
    b LoopCopyDataInit 

CopyDataInit: 
    ldr r3, =_sidata 
    ldr r3, [r3, r1] 
    str r3, [r0, r1] 
    adds r1, r1, #4 

LoopCopyDataInit: 
    ldr r0, =_sdata 
    ldr r3, =_edata 
    adds r2, r0, r1 
    cmp r2, r3 
    bcc CopyDataInit 
    ldr r2, =_sbss 
    b LoopFillZerobss 
/* Zero fill the bss segment. */ 
FillZerobss: 
    movs r3, #0 
    str r3, [r2], #4 

EDIT: Вот разобранная инструкция:

disas 
Dump of assembler code for function Reset_Handler: 
    0x08005dc0 <+0>:  movs r1, #0 
    0x08005dc2 <+2>:  b.n  0x8005dcc <LoopCopyDataInit> 
    0x08005dc4 <+4>:  ldr  r3, [pc, #40] ; (0x8005df0 <LoopFillZerobss+16>) 
=> 0x08005dc6 <+6>:  ldr  r3, [r3, r1] 
    0x08005dc8 <+8>:  str  r3, [r0, r1] 
    0x08005dca <+10>: adds r1, #4 
    0x08005dcc <+0>:  ldr  r0, [pc, #36] ; (0x8005df4 <LoopFillZerobss+20>) 
    0x08005dce <+2>:  ldr  r3, [pc, #40] ; (0x8005df8 <LoopFillZerobss+24>) 
    0x08005dd0 <+4>:  adds r2, r0, r1 
    0x08005dd2 <+6>:  cmp  r2, r3 
    0x08005dd4 <+8>:  bcc.n 0x8005dc4 <Reset_Handler+4> 
    0x08005dd6 <+10>: ldr  r2, [pc, #36] ; (0x8005dfc <LoopFillZerobss+28>) 
    0x08005dd8 <+12>: b.n  0x8005de0 <LoopFillZerobss> 
    0x08005dda <+0>:  movs r3, #0 
    0x08005ddc <+2>:  str.w r3, [r2], #4 
    0x08005de0 <+0>:  ldr  r3, [pc, #28] ; (0x8005e00 <LoopFillZerobss+32>) 
    0x08005de2 <+2>:  cmp  r2, r3 
    0x08005de4 <+4>:  bcc.n 0x8005dda <FillZerobss> 
    0x08005de6 <+6>:  bl  0x8005c64 <SystemInit> 
    0x08005dea <+10>: bl  0x8000184 <main> 
    0x08005dee <+14>: bx  lr 
End of assembler dump. 
+0

Указатель на указатель или программный счетчик? Что такое 0x08005dc6? Пахнет, как ОЗУ. Если ваш автоматический дисплей - указатель стека, измените его на счетчик программ и команду дизассемблирования. Если управление передано типичному обработчику прерываний по умолчанию, SP не будет выполняться, потому что такие обработчики обычно являются просто «прыгающими в себя». –

+0

@MartinJames: Извините, это счетчик программ. – Randomblue

+1

Хммм.Загрузка r3 не кажется очень захватывающей :(Вы уверены, что то, что вы смотрите, на самом деле, как вы думаете, я так много раз сбивал с пути неправильные версии исходных файлов, файлов карт и т. Д. и т. д. –

ответ

4

на основе кода и разборки, вы в курсе, что я предполагаю, что адрес, который находится в _sidata является инвалид. _sidata загружается в r3, поэтому, когда

ldr  r3, [r3, r1] 

выполняется, недействительный доступ вызывает другой сброс процессора, который затем выполняет, пока не достигнет этой инструкции снова. Или что-то типа того.

Проверьте, что находится в _sidata.


Некоторые дополнительные примечания:

Я вижу, что команда по адресу хххх использует r0, но я не вижу, где r0 инициализирован в reset_handler(). Возможно, что код, который вызывает reset_handler(), возможно, правильно настроил r0, но, чтобы точно знать, нам нужно будет увидеть таблицу векторов исключений и код, на который на самом деле указывает вектор сброса. (Я предполагаю, что это для ARM7 или аналогичного - сообщите мне, если я догадался неправильно), где таблица векторов исключений может выглядеть примерно так (заимствовано из ethernut.de), которое будет привязано к метке с именем _start при сбросе :

.global __vectors 
__vectors: 
ldr  pc, [pc, #24] /* Reset */ 
ldr  pc, [pc, #24] /* Undefined instruction */ 
ldr  pc, [pc, #24] /* Software interrupt */ 
ldr  pc, [pc, #24] /* Prefetch abort */ 
ldr  pc, [pc, #24] /* Data abort */ 
ldr  pc, [pc, #24] /* Reserved */ 

/* 
* On IRQ the PC will be loaded from AIC_IVR, which 
* provides the address previously set in AIC_SVR. 
* The interrupt routine will be called in ARM_MODE_IRQ 
* with IRQ disabled and FIQ unchanged. 
*/ 
ldr  pc, [pc, #-0xF20] /* Interrupt request, auto vectoring. */ 
ldr  pc, [pc, #-0xF20] /* Fast interrupt request, auto vectoring. */ 

.word _start 
.word __undef 
.word __swi 
.word __prefetch_abort 
.word __data_abort 
+0

Я думаю, что вы правы, поскольку '_sidata' является недопустимым адресом. Что касается инициализации 'r0', я думаю, что это делается в первой строке' LoopCopyDataInit'. (Сброс обработчика вызывает «LoopCopyDataInit» в качестве второй команды.) – Randomblue

+0

Если загрузка r3 генерирует прерывание данных, не следует ли идентифицировать ее один шаг? –

+0

@MartinJames: вы так думаете, но вы также ожидаете, что выполнение одного шага на 'ldr r3, [r3, r1]' будет продвигать счетчик программ! Я не знаю, какая именно инструментальная цепочка используется или как создаются векторы исключений. Я знаю, что давным-давно, когда я возился с драйвером OpenOCD JTAG и старым плагином Zylin CDT для GDB в Eclipse, ориентированным на ARM7, дела не всегда стабильно вели себя. –

1

Ну, это зависит :-)

Что это зависит от является инструкции по адресу 0x08005dc6. Вполне возможно, что в обработчике сброса вы можете получить такую ​​инструкцию, как:

0x08005dc6 jmp 0x08005dc6 

, который проявил бы это поведение.

Вы должны проверить, чтобы увидеть, что на самом деле в этом месте, что-то вроде:

disas 0x08005dc6 0x08005dcf 
+0

Это действительно счетчик программ, спасибо. Как я могу проверить инструкцию в этом конкретном месте? Должен ли я использовать 'objdump'? – Randomblue

+1

@Randomblue,' objdump', no, если вы не мазохист :-) Поскольку вы 're уже _in_ 'gdb' (используя команду' ni'), просто используйте команду 'disas' в соответствии с моим обновлением. – paxdiablo

+0

Я обновил вопрос с дампа разборки. – Randomblue

Смежные вопросы