Мод Bare-metal (%) зависает на ARMv6 с libgcc

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

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

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

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

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

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

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


person singpolyma    schedule 02.02.2012    source источник
comment
вам нужно изучить дизассемблирование, не могли бы вы выложить соответствующий дизассемблирование для созданной вами программы? Вы запускали это на реальном оборудовании, а не на qemu?   -  person old_timer    schedule 02.02.2012
comment
Я разместил свой дизассемблированный код на singpolyma.net/test.asm (предупреждение: очень большой!) - - У меня нет хорошего доступа к какому-либо реальному оборудованию. Моя цель QEMU.   -  person singpolyma    schedule 02.02.2012


Ответы (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, чтобы добраться туда, то это не должно работать, либо все равно должно произойти сбой...

person old_timer    schedule 02.02.2012
comment
Ссылка на ваш код thumb_test.s и его вызов работают. Добавление -mthumb-interwork в CFLAGS не работает. Хм, удаление .thumb_func из вашего теста вызывает ту же проблему. Таким образом, он не понимает, что этот другой код является большим пальцем, возможно, каким-то образом. Итак, мне нужно найти способ убедить компилятор в том, что он вызывает код большого пальца, чтобы сгенерировать правильный трамплин? - person singpolyma; 04.02.2012
comment
Странно, однако, что изменение основного кода для компиляции в режиме большого пальца не исправляет ситуацию. Разборка: singpolyma.net/test2.asm - person singpolyma; 04.02.2012
comment
там много кода thumb2, arm11 не поддерживает thumb2. Что произойдет, если вы удалите модуль, но скомпилируете с этой версией thumb? - person old_timer; 04.02.2012
comment
когда вы удаляете .thumb_func, ассемблер не знает, что это код большого пальца, предположим, что он работает и делает вызов руки по этому адресу, вы должны использовать .thumb_func или какой-либо другой эквивалент (если есть), чтобы сообщить ассемблеру, что это цель большого пальца ( установите msbit адреса, когда вы его вызываете). в основном вы должны использовать bx или blx для переключения режимов, а младший бит адреса указывает режим (он не используется как адрес, просто бит режима) 1 - большой палец, 0 - рука. - person old_timer; 04.02.2012
comment
поскольку это симулятор, а не настоящий, вам могут сойти с рук некоторые инструкции, не поддерживаемые аппаратно, так что имейте в виду. - person old_timer; 04.02.2012
comment
Я сказал это неправильно, если вы не поместите туда .thumb_func, ассемблер не пометит его как адрес большого пальца, что довольно глупо, потому что ассемблер ДЕЙСТВИТЕЛЬНО знает, что этот раздел кода является кодом большого пальца. компоновщик предположит, что это адрес руки и не закодирует правильный адрес для bx. если вы находитесь в режиме большого пальца и выполняете ldr pc, адрес большого пальца у вас должен быть в порядке. я подозреваю, что вы также можете иметь дело с инструкциями thumb2, которые не поддерживаются ни в делении/по модулю, ни сейчас везде. - person old_timer; 04.02.2012
comment
вы можете найти это уродливым решением, но я часто делаю что-то вроде этого github.com/dwelch67/stm32f4d в в каталоге adventure, тогда gcclib содержит файлы из gcc. Конечно, этот stm32f4d — thumb2, и вам нужна рука или большой палец, тот же подход работает отлично. поместите синтаксическую ошибку в исходный код gcc lib, затем создайте кросс-компилятор, когда он выйдет из строя из-за синтаксической ошибки, украдите командную строку и настройте при необходимости. Обычно я просто никогда не использую деление или модуль. - person old_timer; 04.02.2012