Строка разыменования сборки ARM, получающая только 4 байта - PullRequest
0 голосов
/ 14 ноября 2018

У меня есть следующий код в моей программе сборки ARM

.data

.balign 4
prompt1: .asciz "Enter a string: "

.balign 4
scan1: .asciz "%s"

.balign 4
string_read: .word 0

.text

.global main

main:
  push {fp, lr}
  ldr r0, addr_prompt1
  bl printf

  ldr r0, addr_scan1
  ldr r1, addr_string_arg
  bl scanf

  ldr r2, addr_string_arg
  ldr r2, [r2]



addr_prompt1 : .word prompt1
addr_scan1 : .word scan1
addr_string_arg : .word string_read

Я использую GDB PEDA для отладки.Допустим, я ввел «test_cases» в качестве моей строки.Я вижу, что когда я выполняю

ldr r2, addr_string_arg

, он содержит адрес, который указывает на полную строку «test_cases».Однако после разыменования

ldr r2, [r2]

r2 теперь содержит значение (b'test ').Когда я пытаюсь передать это функции, она становится «test / 002».Это происходит с любой строкой длиной более 4 символов.Я попытался изменить значения рядом с .balign, а также .word, и ни одно из них не помогло.

1 Ответ

0 голосов
/ 15 ноября 2018

Все комментарии по вашему вопросу актуальны, но никто еще не опубликовал фактический ответ , так что вот так!

По своей природе строки имеют переменную длину.По этой причине они почти всегда хранятся в памяти и передаются с помощью указателя на первый символ.Также по соглашению (по крайней мере, в мире C, и вы взаимодействуете с библиотеками C в своем коде), длина строки нигде не сохраняется, а конец строки вместо этого отмечается нулевым байтом.

На самом деле вы используете строки в обычном правильном порядке в нескольких местах вашего кода - например, когда вы получаете адрес addr_prompt для передачи в качестве первого аргумента printf.Когда вы используете инструкцию

ldr r2, addr_string_arg

, вы загружаете адрес первого символа строкового аргумента в r2, и было бы стандартной практикой использовать этот адрес для представления строки.Когда вы впоследствии пишете

ldr r2, [r2]

, вы фактически разыменовываете указатель и загружаете четыре байта (32 бита), начиная с этого адреса, в r2.r2 не содержит строку, только первые четыре байта;и действительно, эти байты могут даже не быть в том же порядке, в каком они были в памяти, в зависимости от порядкового номера вашей системы.

Обратите внимание, что вы должны выделить достаточно места для хранениясамая длинная строка, которую вы когда-либо ожидали, и в данный момент вы этого не делаете (string_read - это всего 4 байта, что с символом завершения допускает трехсимвольную строку).Разрешение строке переполнять ее буфер приводит к неопределенному поведению.

Кроме того, когда вы загружаете произвольные константы (включая адреса) в регистры, псевдоинструкция LDR - это то, что вам нужно - издесь используется знак равенства перед вторым аргументом.Это может собирать в несколько инструкций, в зависимости от загружаемой константы;для соседних адресов он часто реализуется как относящийся к ПК ADD, но вам не нужно об этом беспокоиться, когда вы его используете.Например,

ldr r2, =string_read

устраняет необходимость в addr_string_arg.

...