将值插入数组并显示,nasm

Insert values into array and display, nasm

首先,这是一项家庭作业。

我有一个循环分别获取两个数字的值,然后通过将第一个数字乘以 10 并与第二个数字相加得到一个整数来加入它们。

我正在做所有这些并保存在我的 AL 寄存器中,现在我想将该整数插入一个数组,然后扫描该数组并显示这些数字。

如何插入向量并从向量中读取?

我的数组:

section .bss
    array resb 200  

我的数字转换:

sub byte[digit_une], 30h
sub byte[digit_two], 30h

mov al, byte[digit_one]         
mov dl, 10                  ;dl = 10
mul dl                      ;al = ax = 10 * digit_one
add al, byte[digit_two]     ;al = al + digit_two = digit_one * 10 + digit_two

"arrays"、"vectors"、等等……都是更高层次的概念。机器有内存,可以单字节寻址,你用你的代码实现什么样的逻辑,那是你的事。但是你应该能够在两个层面上考虑它,作为内存中的单个字节,每个字节都有自己的地址,并且完全理解你的代码逻辑,它将如何安排这些字节的使用以形成 "array of something".

根据您对 .bss 扇区的定义,您定义了一个 symbol/label array,它等于内存中 .bss 段开始的地址。然后你保留 200 个字节的 space,所以你将在后面添加的任何其他内容(如另一个标签)将从地址 .bss+200.

开始

假设(例如)将二进制文件加载到内存并跳转到入口点后,.bss 位于地址 0x1000.

然后

mov dword [array],0x12345678

将 4 个字节存储到地址 0x1000 .. 0x1003 的内存中,特定字节的值为 78 56 34 12(该双字值的小端分解)。

如果你做mov dword [array+199],0x12345678,你会把值0x78写入那个resb 200的最后一个官方保留字节,剩下的3个字节将覆盖地址.bss的内存+200、.bss+201 和 .bss+202(可能会损坏其他一些数据,如果您将某些东西放在那里,或者使您的应用程序崩溃,如果它会跨越内存页面边界,并且您处于可用内存的末尾你的过程)。

因为要将 N byte 个值存储到数组中,最简单的逻辑是将第一个值存储在地址 array+0,第二个在 array+1,等等...(对于 dword 值,最合乎逻辑的方式是 array+0, array+4, array+8, ....)。

mov [array+0],al 可用于存储第一个值。但这不是很实用,如果您正在某种循环中读取输入。假设你想从用户那里读取最多 200 个值,或者值 99 会更快结束,那么你可以使用寄存器索引,比如:

    xor esi,esi  ; rsi = index = 0
    mov ecx,200  ; rcx = 200 (max inputs)
input_loop:

    ; do input into AL = 0..99 integer (preserve RSI and RCX!)
    ...

    cmp al,99
    je  input_loop_terminate
    mov [array+rsi], al   ; store the new value into array
    inc rsi      ; ++index
    dec rcx      ; --counter
    jnz input_loop   ; loop until counter is zero
input_loop_terminate:
    ; here RSI contains number of inputted values
    ; and memory from address array contains byte values (w/o the 99)

即对于用户输入 32、72、13、0、16、99,地址 0x1000 处的内存将修改 5 个字节,现在包含(十六进制):20 48 0D 00 10 ?? ?? ?? ....

如果你有点熟练的 asm 程序员,你不仅会通过寄存器索引,还会避免硬编码 array 标签,所以你可能会做一个子程序,它以目标地址(数组)为参数, 和最大计数:

; function to read user input, rsi = array address, rcx = max count
; does modify many other registers
; returns amount of inputted values in rax
take_some_byte_values_from_user:
    jrcxz .error_zero_max_count  ; validate count argument
    lea rdi,[rsi+rcx]  ; rdi = address of first byte beyond buffer
    neg rcx            ; rcx = -count  (!)
      ; ^ small trick to make counter work also as index
      ; the index values will be: -200, -199, -198, ...
      ; and that's perfect for that "address of byte beyond buffer"
.input_loop:

    ; do input into AL = 0..99 integer (preserve RSI, RDI and RCX!)
    ...

    cmp al,99
    je  .input_loop_terminate
    mov [rdi+rcx], al  ; store the new value into array
    inc rcx            ; ++counter (and index)
    jnz .input_loop    ; loop until counter is zero
.input_loop_terminate:
    ; calculate inputted size into RAX
    lea rax,[rdi+rcx]  ; address beyond last written value
    sub rax,rsi        ; rax = count of inputted values
    ret

.error_zero_max_count:
    xor eax,eax        ; rax = 0, zero values were read
    ret

然后你可以像这样从主代码调用那个子程序:

    ...
    mov   rsi,array    ; rsi = address of reserved memory for data
    mov   ecx,200      ; rcx = max values count
    call  take_some_byte_values_from_user
    ; keep RAX (array.length = "0..200" value) somewhere
    test  al,al        ; as 200 was max, testing only 8 bits is OK
    jz    no_input_from_user  ; zero values were entered
    ...

对于 word/dword/qword 元素数组,x86 在内存操作数中具有比例因子,因此您可以使用 +1 的索引值和地址值,如:

    mov   [array+4*rsi],eax  ; store dword value into "array[rsi]"

对于其他大小的元素,使用指针而不是索引通常更有效,并通过像 add rdi,96 那样执行 add <pointer_reg>, <size_of_element> 移动到下一个元素,以避免每次访问的索引值相乘。

等...以相同的方式读回值,但操作数相反。

顺便说一句,这些示例没有像 "overwrite" 那样将尽可能多的 "insert" 值放入数组中。计算机内存已经存在并具有一些值(.bss 被 libc 或 OS IIRC 清零?否则可能会有一些垃圾),所以它只是用用户的值覆盖旧的垃圾值。 resb 仍有 200 字节的内存 "reserved",您的代码必须跟踪实际大小(输入值的计数)以了解用户输入的结束位置以及垃圾数据的开始位置(或者您最终可能会将 99 值也写入数组,并将其用作 "terminator" 值,然后您只需要数组的地址来扫描它的内容,并在找到值 99 时停止)。

编辑:

以防万一你仍然想知道为什么我有时使用方括号有时不使用,这个 Q+A 看起来足够详细并且 YASM 语法与 NASM 相同,在括号用法中:Basic use of immediates (square brackets) in x86 Assembly and yasm