Как найти максимальное значение заданного значения и адрес переменной на языке ассемблера?

#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]
  

Итак, вам нужно будет просмотреть весь ваш код, а не одну строку, которую вы нам отправили.