Может кто-нибудь показать мне, что я делаю не так?
Вы не использовали отладчик: http://idownvotedbecau.se/nodebugging/
Программирование в сборке без отладчика похоже на попытку собрать робота с завязанными глазами. Это возможно, но это занимает гораздо больше времени (от 10 до 100 раз сложнее, без шуток), умения и усилий.
Я не могу найти, каков ваш «оружейный» на самом деле, и где у него есть некоторая документация, так что проверьте себя или обратитесь к поставщику ПО за документацией + помощь. Но для этого обязательно должен быть какой-то отладчик, иначе просто найдите другой симулятор / эмулятор ARM с разными инструментами, потому что нет смысла изучать сборку ARM на враждебной платформе. Машинный код, который вы изучите в другом симуляторе ARM, будет в основном таким же (хотя службы, специфичные для платформы, такие как svc 0x55
, могут быть совершенно разными и, возможно, некоторый синтаксис в ассемблере, как в мире PC x86, существует около 10 различных синтаксисов для ассемблера и иногда это может сбивать с толку, если источник не содержит информации о том, какой синтаксис он использует).
Это был ответ на ваш вопрос, ниже приведены некоторые примечания о вашем коде:
cmp R5, #3
Если ваша платформа явно не указывает состояние значений после выполнения вашего кода, использование неинициализированных регистров является плохой практикой. Я не проверял вашу конкретную платформу, но обычно в таких симуляторах обучения регистры обнуляются, но это не гарантируется, т. Е. Создатели симулятора должны были бы вложить в них случайные значения, чтобы на ранних этапах узнать людей, как это работает. на самом деле.
Так что этот сравнивает неизвестное значение в R5
с 3.
str r1, [R4]
Если svc
не изменяет значение в регистрах (вероятно, нет, догадываясь по экрану вывода, но вы должны знать ), это будет сохранено в памяти по адресу R4
символьное значение (адрес памяти) produto_nome
.
Итак, после того, как ваш первый [входной] цикл завершен (который называется Loop
, в отличие от цикла печати, который называется readloop
... Вы, вероятно, должны рассмотреть карьеру в бизнесе обфускатора, я вижу здесь некоторый талант ) содержимое памяти в разделе .data
выглядит примерно так (вручную «разбирают» обратно в исходный код, но вы должны попытаться проверить в отладчике вашего симулятора, как вы можете просматривать фактическое содержимое памяти, одновременно переходя по одной инструкции) :
i:
.word produto_nome
.word produto_nome
.word produto_nome
produto_nome:
.ascii "your last input", "remains of previous longer inputs"
.skip <remaining bytes to 100>
@ ^ = maybe zeroes, if your platform zeroes .data segment
quebra_linha:
.ascii "\r\n\r" @ on any decent platform "\n" is enough for newline
@ (DOS and Windows are different, but those are obsolete and dead)
Как вы можете видеть, в памяти есть только последний вход в качестве завершенного (и даже там у вас нет никакого способа узнать, где он заканчивается), предыдущие входы перезаписываются им (вы можете попробовать, введя "aaaaa", "bbb", "c" и посмотрите, что получится, это также покажет вам, является ли символ новой строки или нулевой терминатор частью ввода или нет, если ввод - просто чистые строковые данные, то результат должен быть " cbbaa».
В ассемблере у вас есть только физическая память в чипе, поэтому она не растет динамически, как обычные переменные в более высоких языках программирования.
Вам нужно будет решить, как вы хотите, чтобы ваш массив строк хранился в памяти, так как есть много опций:
- самая несжатая компактная форма, такая как
"aaaaa\0bbb\0c\0"
, которая занимала бы только 12 байтов, но трудно получить доступ к «случайному» индексу i , так как вы должны каждый раз искать весь контент с самого начала и считать завершающие нули, пока вы не найдете начало i -ой строки (кстати, вам не нужен «произвольный» доступ в цикле печати, поскольку вы печатаете все значения последовательно, поэтому эта форма является разумным выбором для текущей код, но это будет немного медленнее для приложения с произвольным доступом, но он будет использовать меньше памяти ... решения, решения ... Обычно эта форма используется для таких вещей, как аргументы командной строки, но есть дополнительный массив указателей, указывая на начало каждой строки, чтобы вы получили как хорошую производительность, так и компактное использование памяти)
- самая простая форма, резервирующая 3x100 байт, поэтому каждая входная строка начинается с адреса «массив + i * 100».
- массив указателей 3x4 байта, как у вас сейчас, но вы также должны зарезервировать место для хранения ввода в другом месте, вероятно, снова 3x100 байтов, как в предыдущем случае, и хранить указатели на это пространство, а не фиксированное значение
produto_nome
.
Самое простое решение для новичка - использовать большой буфер памяти N * TAM и вычислять указатели на строки как array_buffer + i * TAM
.
Также, если вы измените TAM
на 128 вместо 100 (попробуйте использовать в сборке вместо «округленных» значений, таких как 128, не округленные значения, такие как 100, в некоторых ситуациях намного сложнее обрабатывать для компьютера. ... о, кстати, если вы думаете, что "100" округлено, а "128" нет, попробуйте просмотреть их в двоичном виде, вот как их видит компьютер ...), вы можете умножить i
, просто сдвинув его влево 7 раз (т.е. lsl R4, R5, #7
), чтобы получить значение i*128
.
Так что я бы изменил эти сдвиги в вашем коде, тогда память после метки i:
должна быть зарезервирована как .skip TAM*3
(если ваш ассемблер способен вычислять выражения во время компиляции, в противном случае вам придется использовать .skip 384
), и сделайте входное чтение, чтобы нацелить память массива напрямую, без дополнительного буфера produto_nome
, чтобы вам не нужно было копировать 128 байтов строки в буфер массива после svc 0x55
.
Также проверьте, что именно делает служба mov r0, #0
, завершает ли она строку нулем или нет, и возвращает ли она длину где-нибудь или нет. И вам, вероятно, следует печатать только введенную длину данных, а не весь буфер TAM
(если только служба печати #1
не завершает работу после нулевого терминатора или чего-то еще, но выглядит как обычная служба write(...)
, т.е. она будет выводиться в полный буфер консоли, включая ненужную после ввода текста пользователем.