Если вы задали вопрос, потому что у вас было задание, ваша цель, вероятно, заключалась в том, чтобы потратить столько времени, сколько необходимо для выработки собственного, рабочего, решения: по моему скромному мнению, это лучший способ учиться ..
Это проще, чем пошагово собирать, связывать и отлаживать программу aarch64, используя qemu-system-aarch64
, aarch64-elf-as
, aarch64-elf-ld
и aarch64-elf-gdb
.
Это можно сделать в Linuxи Windows - я использовал среду Windows в моем случае.Инструментарий был загружен с здесь и qemu-system-aarch64
с здесь .
Если вы не чувствуете себя достаточно комфортно с базовыми / радикальными преобразованиями, ищите учебниксначала в интернете, например этот .Только тогда вы должны начать работу по поиску решения вашей проблемы.
Документация ARM предоставляет в своих «Исследовательских инструментах», безусловно, является лучшим, ИМХО, когда ее стремление объяснитьПодробные инструкции aarch63.
Ваша проблема может быть разделена на две части:
- преобразование строки в ASCII , то есть "43", в ее двоичный файлпредставление, 101011.
- преобразование двоичного числа 101011 в его строковое представление, то есть "101011".
В приведенном ниже примере не выполняется проверка входных данных, как обычноdo:
/* ----------------------------------------------------
* A minimalist section of code for converting a
* zero-terminated string representating a decimal
* number into a zero-terminated string representating
* a binary number.
* --------------------------------------------------*/
.title "dec2bin.s"
.arch armv8-a
.text
.section .text.startup,"ax"
.globl Reset_Handler
Reset_Handler: ldr x0, =decimalsz // load address of decimalsz into x0.
mov x2, xzr // use x2 for computing the binary value - initial value is zero.
decascii2bin: ldrb w1, [x0], #1 // load byte pointed by x0, then increment x0 by 1.
cbz x1, bin2binascii // if x1 does contain zero, we reached the end of the input buffer.
sub w1, w1, #'0' // x1 does contain the ASCII value for character '4' or '3' - substracting ASCII value for '0'.
// we need to multiply the previous result by 10, then add the current digit:
add x3, xzr, x2, lsl #3 // x3 = 0 + x2 << 3, i.e. 8 * x2
add x2, x3, x2, lsl #1 // x2 = x3 + x2 < 1, i.e. 8 * x2 + 2 * x2 = 10 *x2
add x2, x2, x1 // if we are processing '4', x2 = x2 (0) * 10 + 4 = 4. if we are processing '43, x2 = x2 (40) * 10 + 3 = 43.
bl decascii2bin
bin2binascii: // x2 does now contain 43.
ldr x0, =binarysz // load address of binarysz into x0.
add x0, x0, #64 // x0 points to the byte which would contain the zero-termination if 32 bits were to be displayed.
clz x1, x2 // retrieve the number of bits set to zero for the number contained in x2.
sub x0, x0, x1 // number 43 begins with 58 zero bits, therefore we will only display 64 - 58 = 6 bits.
strb wzr, [x0], #-1 // store zero at binarysz + 6.
movk x3, #'0' // store '0' in x3.
nextbit: bfxil x3, x2, #0, #1 // extract 1 from x2 starting from most significant bit 0, and insert at low end of x3, leaving other bits unchanged.
strb w3, [x0], #-1 // store '0' or '1' to the byte location pointed by x0, then decrement x0 by one.
lsr x2, x2, #1 // shift x2 to the right by one bit.
add x1, x1, #1 // increment number of leading zero bits + number of bits processed, 58 + 1 at first pass, up to 64.
cmp x1, #64 // we are done of 64 bits were leading zero bits or processed.
b.ne nextbit
done: b.al done
.balign 16
// maximum possible value for un unsigned uint_64_t in decimal is:
// 18446744073709551615.
decimalsz: .asciz "43"
// maximum possible value for un unsigned uint_64_t in binary is:
// 1111111111111111111111111111111111111111111111111111111111111111.
// we need at most 65 bytes for 64 digits and a \0.
binarysz: .asciz "0000000000000000000000000000000000000000000000000000000000000000"
.end
Сборка / связывание примера:
aarch64-elf-as -g -adhln -o dec2bin.o dec2bin.s > dec2bin.lst
aarch64-elf-ld -gc-sections -g -e Reset_Handler -Ttext-segment=0x42000000 -Map=dec2bin.map -o dec2bin.elf dec2bin.o
Запуск qemu:
qemu-system-aarch64 -m 256M -semihosting -machine virt,gic-version=2,secure=on,virtualization=on -S -gdb tcp::1234,ipv4 -monitor telnet:127.0.0.1:1235,server,nowait -cpu cortex-a53 -nographic -kernel dec2bin.elf
Запуск GDB (в другой консоли Windows / оболочке Linux):
aarch64-elf-gdb dec2bin.elf
GNU gdb (GDB) 8.2
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=x86_64-w64-mingw32 --target=aarch64-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from src\dec2bin\dec2bin.elf...done.
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
Reset_Handler () at dec2bin.s:13
13 ldr x0, =decimalsz // load address of decimalsz into x0.
Теперь вы можете выполнять программу шаг за шагом и проверять регистры и выходной буфер, используя команды stepi
, p/x {$x0, $x1, $x2, $x3}
и x/s binarysz
.
ВВремя, которое вы достигнетеn проверьте результат, затем выйдите из GDB:
35 done: b.al done
(gdb) p/x {$x0, $x1, $x2, $x3}
$9 = {0x42000062, 0x40, 0x0, 0x31}
(gdb) x/s binarysz
0x42000063 <binarysz>: "101011"
(gdb) kill
Kill the program being debugged? (y or n) y
[Inferior 1 (Remote target) killed]
(gdb) quit