برنامه نویسی

آزمایشگاه 5 (AARCH64) – آزمایشگاه زبان مونتاژ 64 بیتی

مقدمه

سلام به همه! در آزمایشگاه 5 ، ما از جلو حرکت می کنیم 6502 زبان مونتاژ به پردازنده های مدرن مانند x86 وت aarch64بشر هر چند 6502 IS یک مجموعه دستورالعمل حداقل ارائه می دهد ، این پردازنده های مدرن دارای قابلیت ها و معماری بسیار پیشرفته تری هستند. در این آزمایشگاه ، ما به بررسی زبانهای مونتاژ در آنها خواهیم پرداخت.

این پست وبلاگ عمدتا در مورد AArch64 سرور یک قسمت 2 برای این آزمایشگاه وجود دارد که هر آنچه در اینجا کدگذاری شده است در آن کدگذاری می شود x86بشر

تمام آزمایشات انجام خواهد شد x86 وت aarch64 سرورهای از راه دور.

تنظیم کردن

در سرورهای کلاس ما ، نمونه های کد از طریق مسیر به دست می آیند: /public/spo600-assembler-lab-examples.tgzبشر

ما این را استخراج خواهیم کرد .tgz پرونده با استفاده از دستور tarبشر

tar xvf /public/spo600-assembler-lab-examples.tgz
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

کد در این ساختار ارائه خواهد شد:

 spo600
 └── examples
     └── hello                     # "hello world" example programs
         ├── assembler
         │   ├── aarch64           # aarch64 gas assembly language version
         │   │   ├── hello.s
         │   │   └── Makefile
         │   ├── Makefile
         │   └── x86_64            # x86_64 assembly language versions
         │       ├── hello-gas.s   # ... gas syntax
         │       ├── hello-nasm.s  # ... nasm syntax
         │       └── Makefile
         └── c                     # Portable C versions
             ├── hello2.c          # ... using write()
             ├── hello3.c          # ... using syscall()
             ├── hello.c           # ... using printf()
             └── Makefile
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید


AArch64 برنامه مجمع

اول ، ما نگاه خواهیم کرد aarch64 سرور وارد شوید و به فهرست مثال مونتاژ AARCH64 بروید:

cd ~/spo600/examples/hello/assembler/aarch64
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

وجود دارد hello.s پرونده این پرونده منبع کد ماست!

بعد ، خواهید دید که وجود دارد Makefile در این مکان این بدان معنی است که ما می توانیم اجرا کنیم make و برنامه ما را کامپایل کنید. برنامه را با استفاده از make فرمان

بر اساس وابستگی های تعریف شده در Makefileبا make تعیین می کند که کدام قسمت از کد تغییر کرده و نیاز به بازسازی مجدد دارد ، سپس دستورات لازم را برای به روزرسانی فقط آن قسمت ها اجرا می کند.

make
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

پس از این ، یک پرونده باینری به نام خواهید دید hello در فهرست این پرونده باینری حاصل را اجرا کنید.

./hello
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این به شما نشان می دهد “سلام ، جهان!” در ترمینال شما

خوب ، حالا بیایید با استفاده از کد نگاهی بیندازیم objdump فرمان من می خواهم خروجی جدا شده پرونده شی را مقایسه کنم (hello.o) به پرونده منبع (hello.s).

objdump -d hello.o > hello_disassembled.txt
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

  • خروجی جدا شده (hello.o)
hello.o:     file format elf64-littleaarch64


Disassembly of section .text:

0000000000000000 <_start>:
   0:   d2800020        mov     x0, #0x1                        // #1
   4:   10000001        adr     x1, 0 <_start>
   8:   d28001c2        mov     x2, #0xe                        // #14
   c:   d2800808        mov     x8, #0x40                       // #64
  10:   d4000001        svc     #0x0
  14:   d2800000        mov     x0, #0x0                        // #0
  18:   d2800ba8        mov     x8, #0x5d                       // #93
  1c:   d4000001        svc     #0x0
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

.text
.globl _start
_start:

        mov     x0, 1           /* file descriptor: 1 is stdout */
        adr     x1, msg         /* message location (memory address) */
        mov     x2, len         /* message length (bytes) */

        mov     x8, 64          /* write is syscall #64 */
        svc     0               /* invoke syscall */

        mov     x0, 0           /* status -> 0 */
        mov     x8, 93          /* exit is syscall #93 */
        svc     0               /* invoke syscall */

.data
msg:    .ascii      "Hello, world!\n"
len=    . - msg
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

با نگاهی به این دو پرونده ، فایل جداسازی یک ترجمه دقیق دستورالعمل توسط دستورالعمل به کد دستگاه از پرونده منبع ما است. تنها تفاوت این است که ما از آن استفاده می کنیم msg برچسب در adr دستورالعمل با این حال ، این ناشی از ماهیت نحوه نمایش نمادها در کد جدا شده است.


اصلاح AArch64 برنامه مجمع

در اینجا یک حلقه اساسی در مونتاژ AARCH64 وجود دارد.

 .text
 .globl _start
 min = 0                          /* starting value for the loop index; **note that this is a symbol (constant)**, not a variable */
 max = 6                         /* loop exits when the index hits this number (loop condition is i
 _start:
     mov     x19, min
 loop:

     /* ... body of the loop ... do something useful here ... */

     add     x19, x19, 1     /* increment the loop counter */
     cmp     x19, max        /* see if we've hit the max */
     b.ne    loop            /* if not, then continue the loop */

     mov     x0, 0           /* set exit status to 0 */
     mov     x8, 93          /* exit is syscall #93 */
     svc     0               /* invoke syscall */
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

کد 6 بار در حال حلقه است (max 6) است. شاخص حلقه را در ثبت 19 ذخیره می کند (x19) برای پیگیری تکرارها. بدنه حلقه در حال حاضر خالی است.

☑ حلقه چاپ

بیایید این کد را به طوری تغییر دهیم که “حلقه” را در هر تکرار چاپ کند. ما اضافه کردیم .data بخش و چاپ را در بدنه حلقه اضافه کنید.
تغییر hello.s مانند زیر:

.text
.globl _start

min = 0                          /* starting value for the loop index */
max = 6                          /* loop exits when the index hits this number */

_start:
    mov     x19, min            /* initialize loop counter */
loop:
    /* Print "Loop" message */
    mov     x0, 1               /* file descriptor: 1 is stdout */
    adr     x1, msg             /* message location (memory address) */
    mov     x2, len             /* message length (bytes) */
    mov     x8, 64              /* write is syscall #64 */
    svc     0                   /* invoke syscall */

    add     x19, x19, 1         /* increment the loop counter */
    cmp     x19, max            /* see if we've hit the max */
    b.ne    loop                /* if not, then continue the loop */

    mov     x0, 0               /* set exit status to 0 */
    mov     x8, 93              /* exit is syscall #93 */
    svc     0                   /* invoke syscall */

.data
msg:    .ascii      "Loop\n"
len=    . - msg
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

با استفاده از این کد جدید را آزمایش کنید make و دویدن

make clean
make
./hello
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

خروجی:

[kzaw@aarch64-002 aarch64]$ ./hello
Loop
Loop
Loop
Loop
Loop
Loop
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

☑ حلقه چاپ و شماره فهرست

بیایید دوباره کد را تغییر دهیم تا چاپ شود Loop: # جایی که '#' شماره شاخص فعلی است.

برای انجام این کار ، ما باید شماره پیشخوان حلقه خود را به نمایش شخصیت ASCII آن تبدیل کنیم. در ASCII/ISO-8859-1/UNICODE UTF-8 ، شخصیت های رقمی در محدوده 48-57 (0x30-0x39) قرار دارند.

add     x20, x19, #48       /* x20 = x19 + 48 (ASCII '0') */
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این پیشخوان حلقه را در Register 19 تبدیل می کند (x19) با افزودن 48 مقدار (کد ASCII برای “0”) و مقدار جدید را در آن ذخیره می کند x20بشر به عنوان مثال ،

  • کی x19 = 0 ، x20 48 می شود (ASCII '0').
  • کی x19 = 1 ، x20 49 می شود (ASCII '1').
  • و غیره …

بعد ، پیام ما را تعریف کنید.

msg:    .ascii      "Loop: #\n"    /* # is a placeholder for the digit */
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

من این کد زیر را به بدنه حلقه اضافه کردم. آنچه در اینجا اتفاق می افتد این است که من آدرس آن را می گیرم msg، و سپس اضافه کردن یک جبران 6 بایت برای اشاره به موقعیت بعد از “حلقه:”. (که طول آن 6 کاراکتر است).

در strb دستورالعمل یک بایت را از یک رجیستر به یک حافظه می نویسد.

w20 نمای 32 بیتی است x20بشر وقتی با استفاده از strb، این بدان معنی است که ما کمترین 8 بیت (1 بایت) را از آن ثبت می کنیم. در این زمینه ، کجا x20 با اشاره به یک رقم ASCII (که 1 بایت طول می کشد) ، دستورالعمل 24 بیت دیگر را نادیده می گیرد و اطمینان می دهد که فضای غیر ضروری صورت نمی گیرد.

[x21] موقعیت مکانی برای ذخیره رقم ASCII در. اکنون این همه چیز به این معنی است که دستورالعمل می نویسد که رقم ASCII به محل حافظه که به آن اشاره شده است x21 ('#').

adr     x21, msg            /* Get address of message */
add     x21, x21, #6        /* Position of the digit character (after "Loop: ") */
strb    w20, [x21]          /* Store the ASCII character at that position */
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید


کد اصلاح شده:

.text
.globl _start

min = 0                          /* starting value for the loop index */
max = 6                          /* loop exits when the index hits this number */

_start:
    mov     x19, min            /* initialize loop counter */
loop:
    /* Convert loop counter to ASCII character */
    add     x20, x19, #48       /* x20 = x19 + 48 (ASCII '0') */

    /* Store the ASCII digit in the message */
    adr     x21, msg            /* Get address of message */
    add     x21, x21, #6        /* Position of the digit character (after "Loop: ") */
    strb    w20, [x21]          /* Store the ASCII character at that position */

    /* Print message with loop counter */
    mov     x0, 1               /* file descriptor: 1 is stdout */
    adr     x1, msg             /* message location (memory address) */
    mov     x2, len             /* message length (bytes) */
    mov     x8, 64              /* write is syscall #64 */
    svc     0                   /* invoke syscall */

    add     x19, x19, 1         /* increment the loop counter */
    cmp     x19, max            /* see if we've hit the max */
    b.ne    loop                /* if not, then continue the loop */

    mov     x0, 0               /* set exit status to 0 */
    mov     x8, 93              /* exit is syscall #93 */
    svc     0                   /* invoke syscall */

.data
msg:    .ascii      "Loop: #\n"    /* # is a placeholder for the digit */
len=    . - msg
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

خروجی:

[kzaw@aarch64-002 aarch64]$ ./hello
Loop: 0
Loop: 1
Loop: 2
Loop: 3
Loop: 4
Loop: 5
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

☑ حلقه از 00 – 32

نیاز بعدی حلقه از 00 – 32 است ، چاپ در اعداد اعشاری 2 رقمی. علاوه بر تغییر max نماد 33 ، تغییرات مهم دیگری نیز وجود دارد که باید انجام دهیم.

پیشخوان حلقه را در x22 کپی می کنیم.

mov     x22, x19            /* Copy loop counter to x22 */
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در مرحله بعد ، ما باید کد خود را تغییر دهیم تا برای تبدیل دو رقمی تهیه کنیم.
پیش از این ، فقط شماره ASCII را به پیشخوان ما اضافه می کرد و همین بود. اکنون پیچیده تر است.

نحوه محاسبه رقم TENS اساساً توسط 10 تقسیم می شود. udiv دستورالعمل در بخش تقسیم می شود.

اینقدر x20 = x22 / 10

/* Calculate tens digit: quotient of division by 10 */
mov     x23, #10            /* Set divisor to 10 */
udiv    x20, x22, x23       /* x20 = x22 / 10 (quotient = tens digit) */
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اکنون که رقم TENS استخراج شده است ، می توانیم با بدست آوردن باقیمانده ، رقم آن را بدست آوریم. برای انجام این کار ، ما استفاده خواهیم کرد mul برای چند برابر با 10. این مقدار از مقدار اصلی برای بدست آوردن باقی مانده از مقدار اصلی کم می شود.

/* Calculate ones digit: remainder of division by 10 */
mul     x24, x20, x23       /* x24 = quotient * 10 */
sub     x21, x22, x24       /* x21 = original - (quotient * 10) = remainder */
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

بعد از همه اینها ، می توانیم همه چیز را به ASCII تبدیل کنیم.

/* Convert digits to ASCII */
add     x20, x20, #48       /* Convert tens digit to ASCII */
add     x21, x21, #48       /* Convert ones digit to ASCII */
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

بگذارید یک جدول از ثبت ها را به شما نشان دهم ، با مقایسه قدیمی و جدید ، تا بتوانیم بهتر درک کنیم.

ثبت نام هدف اصلی هدف جدید
X19 شمارنده حلقه پیشخوان حلقه (بدون تغییر)
x20 رقم ASCII ده رقمی (پس از تبدیل به ASCII)
x21 نشانگر پیام رقم آن (پس از تبدیل به ASCII)
x22 کپی پیشخوان حلقه برای محاسبات
x23 مقدار ثابت 10 (تقسیم کننده)
x24 اشاره گر برای دستکاری بافر پیام

محاسبه تکمیل شده است! منطقی را تغییر دهید که پیام را تغییر می دهیم تا دو رقم را در خود جای دهد.

/* Store the ASCII digits in the message */
adr     x24, msg            /* Get address of message */
add     x24, x24, #6        /* Position of the first digit (after "Loop: ") */
strb    w20, [x24]          /* Store the tens digit */
add     x24, x24, #1        /* Move to the position of the second digit */
strb    w21, [x24]          /* Store the ones digit */
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید


کد اصلاح شده:

.text
.globl _start

min = 0                          /* starting value for the loop index */
max = 33                         /* loop exits when the index hits this number */

_start:
    mov     x19, min            /* initialize loop counter */
loop:
    /* Convert loop counter to two ASCII digits */
    mov     x22, x19            /* Copy loop counter to x22 */

    /* Calculate tens digit: quotient of division by 10 */
    mov     x23, #10            /* Set divisor to 10 */
    udiv    x20, x22, x23       /* x20 = x22 / 10 (quotient = tens digit) */

    /* Calculate ones digit: remainder of division by 10 */
    mul     x24, x20, x23       /* x24 = quotient * 10 */
    sub     x21, x22, x24       /* x21 = original - (quotient * 10) = remainder */

    /* Convert digits to ASCII */
    add     x20, x20, #48       /* Convert tens digit to ASCII */
    add     x21, x21, #48       /* Convert ones digit to ASCII */

    /* Store the ASCII digits in the message */
    adr     x24, msg            /* Get address of message */
    add     x24, x24, #6        /* Position of the first digit (after "Loop: ") */
    strb    w20, [x24]          /* Store the tens digit */
    add     x24, x24, #1        /* Move to the position of the second digit */
    strb    w21, [x24]          /* Store the ones digit */

    /* Print message with loop counter */
    mov     x0, 1               /* file descriptor: 1 is stdout */
    adr     x1, msg             /* message location (memory address) */
    mov     x2, len             /* message length (bytes) */
    mov     x8, 64              /* write is syscall #64 */
    svc     0                   /* invoke syscall */

    add     x19, x19, 1         /* increment the loop counter */
    cmp     x19, max            /* see if we've hit the max */
    b.ne    loop                /* if not, then continue the loop */

    mov     x0, 0               /* set exit status to 0 */
    mov     x8, 93              /* exit is syscall #93 */
    svc     0                   /* invoke syscall */

.data
msg:    .ascii      "Loop: ##\n"   /* ## are placeholders for the two digits */
len=    . - msg
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

خروجی:

[kzaw@aarch64-002 aarch64]$ ./hello
Loop: 00
Loop: 01
...
Loop: 09
Loop: 10
...
Loop: 32
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

☑ حلقه بدون دنباله صفرا

تغییر بعدی که ما ایجاد می کنیم حذف صفر پیشرو برای شماره های تک رقمی است.

برای تحقق این امر ، ما باید پیاده سازی کنیم مشروط منطقی که تشخیص می دهد که آیا ما با یک شماره تک رقمی یا دو رقمی سر و کار داریم و بر این اساس خروجی را قالب بندی می کنیم.

ما باید بسته به مقدار شماره از قالب های مختلف پیام استفاده کنیم:

  • برای اعداد 0-9: از “حلقه: #” استفاده کنید (به دو فضای بعد از روده بزرگ توجه کنید)
  • برای شماره های 10-32: از “حلقه: ##” استفاده کنید (به یک فضا بعد از روده بزرگ توجه کنید)
.data
msg1:   .ascii      "Loop:  #\n"   /* Single-digit format (note: two spaces after colon) */
len1=   . - msg1
msg2:   .ascii      "Loop: ##\n"   /* Double-digit format (note: one space after colon) */
len2=   . - msg2
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در کلید تغییر این بررسی مشروط است. ما ده رقم را با مقدار ASCII “0” مقایسه می کنیم. اگر این “0” نباشد ، می دانیم که یک شماره دو رقمی داریم. ما جدید خواهیم ساخت double_digit عملکرد برای شرایط ما.

/* Determine if number is single or double digit */
cmp     x20, #48            /* Compare tens digit to ASCII '0' */
b.ne    double_digit        /* If not '0', it's a double-digit number */
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اگر این رقم دو رقمی نباشد ، ما به پرونده تک رقمی ادامه می دهیم. استفاده کردن msg1 و در موقعیت 6 ذخیره کنید. پس از منطق ، به سمت مشترک پرش کنید print_msg روال

/* Single-digit case (0-9) */
adr     x24, msg1           /* Get address of single-digit message */
strb    w21, [x24, #6]      /* Store ones digit at position after "Loop: " */
mov     x1, x24             /* Set message address for print */
mov     x2, len1            /* Set message length */
b       print_msg           /* Jump to print routine */
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اگر این رقم دو رقمی باشد ، ما به آن می پرید double_digit روال استفاده کردن msg2، طول و آدرس را برای چاپ تنظیم کنید و سپس به منطق چاپ بروید.

double_digit:
    /* Double-digit case (10-32) */
    adr     x24, msg2           /* Get address of double-digit message */
    strb    w20, [x24, #6]      /* Store tens digit */
    strb    w21, [x24, #7]      /* Store ones digit */
    mov     x1, x24             /* Set message address for print */
    mov     x2, len2            /* Set message length */
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این منطق چاپ زیر است.

print_msg:
    /* Print message with loop counter */
    mov     x0, 1               /* file descriptor: 1 is stdout */
    mov     x8, 64              /* write is syscall #64 */
    svc     0                   /* invoke syscall */
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید


کد اصلاح شده:

.text
.globl _start

min = 0                          /* starting value for the loop index */
max = 33                         /* loop exits when the index hits this number */

_start:
    mov     x19, min            /* initialize loop counter */
loop:
    /* Convert loop counter to two ASCII digits */
    mov     x22, x19            /* Copy loop counter to x22 */

    /* Calculate tens digit: quotient of division by 10 */
    mov     x23, #10            /* Set divisor to 10 */
    udiv    x20, x22, x23       /* x20 = x22 / 10 (quotient = tens digit) */

    /* Calculate ones digit: remainder of division by 10 */
    mul     x24, x20, x23       /* x24 = quotient * 10 */
    sub     x21, x22, x24       /* x21 = original - (quotient * 10) = remainder */

    /* Convert digits to ASCII */
    add     x20, x20, #48       /* Convert tens digit to ASCII */
    add     x21, x21, #48       /* Convert ones digit to ASCII */

    /* Determine if number is single or double digit */
    cmp     x20, #48            /* Compare tens digit to ASCII '0' */
    b.ne    double_digit        /* If not '0', it's a double-digit number */

    /* Single-digit case (0-9) */
    adr     x24, msg1           /* Get address of single-digit message */
    strb    w21, [x24, #7]      /* Store ones digit at position after "Loop:  " */
    mov     x1, x24             /* Set message address for print */
    mov     x2, len1            /* Set message length */
    b       print_msg           /* Jump to print routine */

double_digit:
    /* Double-digit case (10-32) */
    adr     x24, msg2           /* Get address of double-digit message */
    strb    w20, [x24, #6]      /* Store tens digit */
    strb    w21, [x24, #7]      /* Store ones digit */
    mov     x1, x24             /* Set message address for print */
    mov     x2, len2            /* Set message length */

print_msg:
    /* Print message with loop counter */
    mov     x0, 1               /* file descriptor: 1 is stdout */
    mov     x8, 64              /* write is syscall #64 */
    svc     0                   /* invoke syscall */

    add     x19, x19, 1         /* increment the loop counter */
    cmp     x19, max            /* see if we've hit the max */
    b.ne    loop                /* if not, then continue the loop */

    mov     x0, 0               /* set exit status to 0 */
    mov     x8, 93              /* exit is syscall #93 */
    svc     0                   /* invoke syscall */

.data
msg1:   .ascii      "Loop:  #\n"   /* Single-digit format (note: two spaces after colon) */
len1=   . - msg1
msg2:   .ascii      "Loop: ##\n"   /* Double-digit format (note: one space after colon) */
len2=   . - msg2
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

خروجی:

Loop:  0
Loop:  1
Loop:  2
...
Loop:  9
Loop: 10
Loop: 11
...
Loop: 32
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

☑ حلقه با خروجی هگز (0 – 20)

حال ، بیایید بگوییم که می خواهیم به جای اعشاری ، در هگز بازده کنیم. شاخه تک در مقابل دو رقمی را بردارید. این تغییراتی است که می توانید ایجاد کنید.

اکنون به جای 10 به جای 10 تقسیم خواهیم شد. این باعث می شود که مقدار “نیبل بالا” (اولین رقم شش ضلعی) و مابقی “نوک پستان” باشد.

    mov     x23, #16
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

برای هر نوک پستان ، بررسی کنید که آیا مقدار آن کمتر از 10 است. اگر هست ، با اضافه کردن 48 آن را به ASCII تبدیل کنید.'A') ، 11 می شود 66 ('B') ، و غیره

در اینجا این منطق برای نوک پستان بالا آورده شده است. همین مورد در مورد نیبل کم اعمال می شود.

    cmp     x20, #10            /* Check if high nibble is less than 10 */
    blt     high_digit_decimal
    add     x20, x20, #55       /* For hex A-F */
    b       high_digit_done
high_digit_decimal:
    add     x20, x20, #48       /* For digits 0-9 */
high_digit_done:

حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید


کد اصلاح شده:

.text
.globl _start

min = 0                          /* starting value for the loop index */
max = 33                         /* loop exits when the index hits this number */

_start:
    mov     x19, min            /* initialize loop counter */
loop:
    /* Convert loop counter to two hexadecimal digits */
    mov     x22, x19            /* Copy loop counter to x22 */

    /* Calculate high nibble: quotient of division by 16 */
    mov     x23, #16            /* Set divisor to 16 for hex */
    udiv    x20, x22, x23       /* x20 = x22 / 16 (high nibble) */

    /* Calculate low nibble: remainder of division by 16 */
    mul     x24, x20, x23       /* x24 = high nibble * 16 */
    sub     x21, x22, x24       /* x21 = original - (high nibble * 16) = low nibble */

    /* Convert high nibble to ASCII */
    cmp     x20, #10            /* Check if high nibble is less than 10 */
    blt     high_digit_decimal
    /* For hex A-F: add 55 (10+55=65 -> 'A') */
    add     x20, x20, #55       
    b       high_digit_done
high_digit_decimal:
    add     x20, x20, #48       /* For digits 0-9: add 48 ('0') */
high_digit_done:

    /* Convert low nibble to ASCII */
    cmp     x21, #10            /* Check if low nibble is less than 10 */
    blt     low_digit_decimal
    /* For hex A-F */
    add     x21, x21, #55       
    b       low_digit_done
low_digit_decimal:
    add     x21, x21, #48       /* For digits 0-9 */
low_digit_done:

    /* Store the ASCII characters in the message template */
    adr     x24, msg           /* Get address of the message template */
    strb    w20, [x24, #6]      /* Store high nibble at position after "Loop: " */
    strb    w21, [x24, #7]      /* Store low nibble */

    /* Print message */
    mov     x1, x24             /* Set message address for print */
    mov     x2, len             /* Set message length */
    mov     x0, 1               /* file descriptor: 1 is stdout */
    mov     x8, 64              /* write is syscall #64 */
    svc     0                   /* invoke syscall */

    add     x19, x19, 1         /* increment the loop counter */
    cmp     x19, max            /* see if we've hit the max */
    b.ne    loop                /* if not, then continue the loop */

    mov     x0, 0               /* set exit status to 0 */
    mov     x8, 93              /* exit is syscall #93 */
    svc     0                   /* invoke syscall */

.data
msg:   .ascii      "Loop: ##\n"   /* Message format for hexadecimal output */
len=   . - msg

حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

خروجی:

[kzaw@aarch64-002 aarch64]$ ./hello
Loop: 00
Loop: 01
Loop: 02
Loop: 03
Loop: 04
Loop: 05
Loop: 06
Loop: 07
Loop: 08
Loop: 09
Loop: 0A
Loop: 0B
Loop: 0C
Loop: 0D
Loop: 0E
Loop: 0F
Loop: 10
Loop: 11
Loop: 12
Loop: 13
Loop: 14
Loop: 15
Loop: 16
Loop: 17
Loop: 18
Loop: 19
Loop: 1A
Loop: 1B
Loop: 1C
Loop: 1D
Loop: 1E
Loop: 1F
Loop: 20
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید


افکار نهایی

این آزمایشگاه به من کمک کرد تا به زبان مونتاژ مدرن بیشتر درک و کدگذاری کنم. در داخل AArch64، من به چندین مفاهیم منطق از دستکاری حافظه ، حلقه ها تا رمزگذاری شخصیت عادت کردم! این به من کمک کرد تا درک خود را محکم کنم.

یکی از مهمترین چیزها این است که همه چیز در مونتاژ صریح است. هر شخصیت چاپ شده و هر تکرار حلقه باید با دقت ساخته شود. من کاملاً آگاه شدم که این مونتاژ سطح پایین است و BTS وجود ندارد. مجبور شدم مکانهای حافظه خودم را مدیریت کنم و با پیشخوان های شاخص خود محتاط باشم. این سطح بسیار پایین تر از C است!

در قسمت 2 این آزمایشگاه ، من همان مراحل را اجرا می کنم x86_64 مونتاژ در حالی که منطق ممکن است مشابه باقی بماند ، کنوانسیون های تماس نحوی و سیستم کاملاً متفاوت خواهند بود.

از وقت شما متشکرم به زودی می بینیم! 😄

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا