Голый металлический мод (%) висит на ARMv6 с libgcc

Когда я пытаюсь использовать% в C-коде в моей голой железной программе ARM, ему нужна оболочка из libgcc. Нет проблем, я могу связать это. Когда я это сделаю, компоновщик перестает жаловаться, но затем программа зависает (если я смотрю регистры, они фактически начинают циклически необъяснимым образом) при использовании мода. Комментирование строки с% заставляет программу не зависать таким образом, так что это определенно проблема.

Я построил тривиальный пример проблемы на https://gist.github.com/1724746

Я запускаю тест, используя:

qemu-system-arm -M versatilepb -cpu arm1176 -nographic -kernel kernel.elf | xxd

Затем ^ ax, чтобы выйти из него, и с закомментированной строкой% я получаю байты, которые ожидаю от вывода, но со строкой там я не получаю такой вывод.

Есть идеи, что здесь происходит?

Изменить: кросс-компилятор, который я использую, по умолчанию включен в Ubuntu: https://launchpad.net/gcc-linaro

1 ответ

Таким образом, он загружает r0 и r1 с 2 (ну, это делает плюс одна вещь в текущей задаче +1

10648:  e1a00003    mov r0, r3
1064c:  e51b1010    ldr r1, [fp, #-16]
10650:  eb00fd36    bl  4fb30 <____aeabi_uidivmod_veneer>

Я думаю, что они использовали _veneer для переключения с руки на большой палец, это батут для переключения режимов:

0004fb30 <____aeabi_uidivmod_veneer>:
   4fb30:   e51ff004    ldr pc, [pc, #-4]   ; 4fb34 <____aeabi_uidivmod_veneer+0x4>
   4fb34:   00010905    .word   0x00010905

Это приводит вас к действию по модулю, это код большого пальца, режим большого пальца

00010904 <__aeabi_uidivmod>:
   10904:   2900        cmp r1, #0
   10906:   d0f8        beq.n   108fa <__aeabi_uidiv+0x252>
   10908:   e92d 4003   stmdb   sp!, {r0, r1, lr}
   1090c:   f7ff fecc   bl  106a8 <__aeabi_uidiv>
   10910:   e8bd 4006   ldmia.w sp!, {r1, r2, lr}
   10914:   fb02 f300   mul.w   r3, r2, r0
   10918:   eba1 0103   sub.w   r1, r1, r3
   1091c:   4770        bx  lr
   1091e:   bf00        nop

Так что выглядит, как сделать нормальное деление, а затем умножает результат и вычитает, например,

12345 % 100 = 12345 - ((12345/100)*100) = 12345 - (123*100) = 12345 - 12300 = 45

Интересно, проблема в режиме большого пальца? Arm1176 определенно имеет режим большого пальца, настоящий, и я QEMU могу сделать большой палец.

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

.thumb
.thumb_func
.globl thumb_test
thumb_test:
   add r0,#1
   bx lr

arm-none-linux-gnueabi-as thumb_test.s -o thumb_test.o

или каким бы ни был ваш префикс цепочки инструментов, если он есть, и связать файл.o со всем остальным.

в коде C объявить его как

unsigned int thumb_test ( unsigned int );

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

Еще одна вещь, которую стоит попробовать - это просто прямое деление, посмотреть, работает ли деление, но не по модулю, может быть, проблема в инструкции умножения? Кто знает.

Хм, я думаю, что вижу проблему:

0004fb30 <____aeabi_uidivmod_veneer>:
   4fb30:   e51ff004    ldr pc, [pc, #-4]   ; 4fb34 <____aeabi_uidivmod_veneer+0x4>
   4fb34:   00010905    .word   0x00010905

Вы не можете переключать режимы с помощью ldr, это должен быть bx или blx, он, вероятно, обращается к неопределенному обработчику, когда пытается выполнить код большого пальца в режиме охраны.

У меня есть несколько примеров того, как переключение режимов должно работать, в частности, написано для qemu. Теперь это низкоуровневый пример, например, нет printf, у меня есть вывод uart с возможностью видеть вещи на uart. Если это проблема (переключение в режим большого пальца), то вам нужно проверить, как вы компилируете и связываете свою программу. Вам может потребоваться указать взаимодействие, или вам может понадобиться понять, как была построена ваша цепочка инструментов, если вы не используете ранее цепочку инструментов исходного кода (теперь она используется наставной графикой). это предполагает, что вы используете что-то на основе GNU / GCC.

Если у вас есть способ поместить туда неопределенный обработчик, или если вы можете наблюдать за трассировкой и увидеть, как компьютер падает около адреса 0x0000000, это, вероятно, и происходит. Если вы соберете мою маленькую вещь thumb_test, и она использует ldr вместо bx, то это не должно работать, либо все равно должно произойти сбой...

Другие вопросы по тегам