#assembly #arm #max #memory-address
#сборка #arm #макс #память-адрес
Вопрос:
Я изучаю ARMv7, и вопрос заключается в реализации этого кода:
shvar = max(shvar, x)
Значение переменной x равно R2, адрес shvar находится в R1. Мой вопрос в том, является ли shvar по сути указателем, и мне нужно «разыменовать» его, иначе получить значение, на которое он указывает в памяти?
Я сделал что-то вроде этого:
LDR R3, [R1]
...
Примечание: И мой инструктор сказал: «Повторное чтение из памяти для значения, которое у вас уже есть в R3, нехорошо», мне интересно, имел ли он в виду это.
Комментарии:
1. Здесь недостаточно информации для продолжения, но да, если у вас есть указатель на переменную памяти, и вы хотите использовать значение переменной, вы загружаете его через указатель. После того, как вы загрузили его, у вас есть копия, которую вы можете использовать для сравнения или чего-то еще. Вам не нужно загружать его дважды, поэтому, если у вас уже есть копия, не нужно создавать другую, если нет какой-либо вероятности, что она изменилась (например, из-за того, что вы сделали).
2. В C имена переменных автоматически разыменовываются, чтобы получить значение в памяти, за исключением переменных массива, подобных
int arr[] = {...}
. В asm имена символов — это просто адрес; вы должны позаботиться о загрузке с них.
Ответ №1:
unsigned int max ( unsigned int, unsigned int );
unsigned int test ( void )
{
return(max(4,5) 1);
}
00000000 <test>:
0: e92d4010 push {r4, lr}
4: e3a01005 mov r1, #5
8: e3a00004 mov r0, #4
c: ebfffffe bl 0 <max>
10: e2800001 add r0, r0, #1
14: e8bd8010 pop {r4, pc}
Соглашение о вызовах привязано к комбинации целевого (armv7-a) и выбора авторов компилятора. Компиляторы могут создавать / выбирать свое собственное соглашение о вызовах, им не обязательно соответствовать рекомендованному abi от целевого поставщика, если у целевого поставщика есть abi (что делает arm).
Выше приведен gcc, вы можете видеть, что первый параметр, равный 32 битам (или меньше), переходит в r0, второй r1. И результат возвращается в r0.
unsigned int max ( unsigned int *, unsigned int );
unsigned int test ( void )
{
return(max((unsigned int *)4,5) 1);
}
00000000 <test>:
0: e92d4010 push {r4, lr}
4: e3a01005 mov r1, #5
8: e3a00004 mov r0, #4
c: ebfffffe bl 0 <max>
10: e2800001 add r0, r0, #1
14: e8bd8010 pop {r4, pc}
Так что никакой разницы, bits — это адреса bits, и таковы понятия языков высокого уровня
unsigned int * test ( unsigned int *p )
{
return( p);
}
00000000 <test>:
0: e2800004 add r0, r0, #4
4: e12fff1e bx lr
Это только адрес, когда он используется в качестве адреса для нескольких часов, когда это что-то значит, затем они возвращаются к разрядам.
unsigned int test ( unsigned int *p )
{
return(*p);
}
00000000 <test>:
0: e5900000 ldr r0, [r0]
4: e12fff1e bx lr
Для ARM рекомендуемое соглашение о вызовах r0-r3 считаются изменчивыми, они используются на пути к функции, но функция не должна сохранять их состояние. Если оно соответствует, возвращаемое значение возвращается в r0. Итак, если это соглашение используется используемым вами компилятором, то r3 вполне допустим. Но если это не является частью возврата (маловероятно, если это вообще возможно), тогда вы можете выполнить
ldr r3,[r1]
но перед тем, как ваша функция вернет то, для чего вы используете r3, вы захотите свернуть обратно в возврат или любую функциональность функции. Итак, если вы хотите передать адрес, скажем, в качестве эталона, вы можете сделать это
unsigned int test ( unsigned int timerregaddress, unsigned int numloops );
Вы могли бы сделать что-то вроде этого
ldr r2,[r0] @ read timer
loop:
@ code under test
subs r1,r1,#1
bne loop
ldr r3,[r0] @ read timer
sub r0,r3,r2 @ compute difference in time
bx lr
Если тестируемый код не использует ни один из этих регистров (ну, почти все регистры, которые вы используете, нужно будет нажимать и извлекать в начале и в конце функции), тогда r2 и r3 будут естественным выбором для промежуточных переменных.
Я подозреваю, что комментарий связан с кодом, который вы не показали, вероятно, вы повторно использовали r3, потеряв содержимое того, что вы там хранили, с этой загрузкой.
a = x y;
a = 37 z;
В то время как компилятор может сгенерировать первую строку, вторая строка уничтожает содержимое переменной a, аналогично выполнению
mov r3,#5
ldr r3,[r1]
Итак, вам нужно будет просмотреть весь ваш код, а не одну строку, которую вы нам отправили.