Привет. Кто занимался ассемблером ARM, подскажите в чём разница между следующими кодами условий: HS Unsigned higher or same PL Plus/positive or zero Как по мне - одно и то же. Но флаги разные проверяет. Для каких инструкций есть разница между этими кодами условий?
cppasm PL проверяет знаковый бит N. HS проверяет бит переноса C. В этом собсно и разница. Аналогично в x86 SF и CF. Или между ними тоже разницу объяснить надо? Пример инструкции... ну скажем сложили два беззнаковых числа. Получили большое число (достаточно, чтобы как знаковое оно было отрицательным). При этом N будет выставлен, но, т.к. переноса не было, C будет сброшен. Или тот же ADC работает с C, а не с N.
cppasm Что-то меня увело в сторону различий между C и N вместо HS и PL. И пример соответственно получился не показательным. С другой стороны по аналогии можно придумать все четыре возможных комбинации для флагов C и N: 1) Сложение двух небольших чисел (10 и 15, например): нет переполнения, нет достижения диапазона отрицательных. Соответственно C = 0, N = 0. 2) Сложение 98CA C92B и 9B1 4D22: нет переполнения, но результат в диапазоне отрицательных. Соответственно C = 0, N = 1. 3) Сложение 98CA C92B и 98CA C92B: переполнение, но результат в диапазоне положительных. Соответственно C = 1, N = 0. 4) Сложение 98CA C92B и FFFF FFFF: переполнение и результат в диапазоне отрицательных. Соответственно С = 1, N = 1. Вывод: HS и PL, равно как и флаги, ими проверяемые, ни разу друг от друга не зависят. Откуда взялось: "Как по мне - одно и то же", — непонятно.
Ну начнём с того что в ARM C=1 если заёма не было, и 0 - если был. HS - C=1 (заёма не было) PL - N=0 Теперь откуда взялось. К примеру CMP R0, #0x20 Это установка флагов для R0-0x20. Получается C=1 когда R0>=0x20 N=0 когда R0>=0x20 В чём проблема я уже понял. При проверке флага C R0 надо рассматривать как беззнаковое, а для N - как знаковое. Т.е. при R0=-1 при CMP R0, #0x20 будет C=1 (0xFFFFFFFF>=0x20), N=1 (-1<0x20, 0xFFFFFFFF-0x20=0xFFFFFFDF - знаковое). В общем-то я ещё простой пример нашёл MOV R0, 1, LSL 31 - число отрицательное, а переноса нет.
Просто вот простой пример. Самая дубовая функция: Code (Text): void copy(int *dst, int *src, int size) { while(size>=sizeof(int)) { *dst++ = *src++; size-=sizeof(int); } } Компилируем GCC, получаем: Code (Text): .file "test.c" .text .align 2 .global copy .type copy, %function copy: @ args = 0, pretend = 0, frame = 0 @ frame_needed = 0, uses_anonymous_args = 0 @ link register save eliminated. cmp r2, #3 bxls lr mov r3, #0 .L3: ldr ip, [r1, r3] str ip, [r0, r3] add r3, r3, #4 rsb ip, r3, r2 cmp ip, #3 bhi .L3 bx lr .size copy, .-copy Вопрос - почему вторая команда bxls? Ведь LS - это unsigned higher or same (Z=1 or C=0), а у size тип знаковый. Т.е. если я передам в size (-1) то работать будет неправильно, или я чего-то не понимаю?
cppasm Неважно, какой именно ассемблер, логика у всех одинаковая, только мнемоники и некоторые особенности отличаются. PL -- это проверка знакового бита (старшего разряда числа со знаком), а HS -- флага переноса после команд вычитания или сравнения, поскольку именно он для _беззнаковых_ операндов показывает, кто был больше.
cppasm Эм... во-первых, я говорил о переносе. И там C выставляется как раз тогда, когда перенос произошёл. Во-вторых... ну и что? Если Вам известно назначение CF и SF в x86, то в ARM аналогично. То, что в случае заёма C в ARM не выставляется, сути не меняет, т.к. назначение флага идентично CF в x86. Ну... LS - это вообще-то lower or same. Да... у size тип знаковый. А какой тип у результата работы sizeof? Неявное приведение типа. Думаю, если все sizeof'ы позаменять на 4, то bxls и bhi превратятся в знаковые условия.
дык sizeof() это compile-time оператор, и он, если ничего не путаю, должен давать тот же эффект что и размер написанный как константа.
Ну не знаю, у меня на х86 вопросов не вызывало как-то... А тут инвертированный флаг переноса напрягает. По-моему как раз нет. Вот к примеру описания из официального мануала. CMP: SBC: Кругом инверсия. Да, это я перепутал (опечатка) - unsigned lower or same. Да, так и есть. Не обратил внимания... Неа. Он возвращает size_t. А числовые константы по умолчанию имеют тип int если в него влезают. Аналогом sizeof(int) на 32-битной платформе будет 4u, а не 4.
cppasm Дык SBC и CMP - это вычитание. Там заёмы, а не переносы. А переносы в ADD и CMN, для которых в случае беззнакового переполнения C будет выставляться.
cppasm Это больше дело привычки, сложностей как таковых нет. Правда, есть риск запутаться из-за подобных вещей, так что надо быть внимательным...
Блин точно. У ADD - как раз привычное использование C, и в ADC используется прямое значение. В общем мне как оказалось проще рассматривать С как 33-й бит первого операнда, установленный в 1 для команд вычитания (не было заёма он 1, если был - 0) и в 0 для сложения (не было переполнения он 0, было - 1). Так сложностей ни в чём нет если разобраться. Но вот на х86 CF одинаково работает как для заёма, так и для переполнения. А в ARM вот по другому. Лучше видно в мануал поглядывать
fasmarm +доки: http://arm.flatassembler.net/ топик по fasmarm: http://board.flatassembler.net/topic.php?t=4191 автор fasmarm: revolution, http://board.flatassembler.net