gpt4 book ai didi

arrays - 将值插入数组并显示,nasm

转载 作者:行者123 更新时间:2023-12-04 18:57:23 28 4
gpt4 key购买 nike

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

我有一个循环来分别获取两位数的值,并通过将第一个数字乘以 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

最佳答案

“数组”、“向量”等......所有这些都是更高层次的概念。机器有内存,可以通过单字节寻址,你用你的代码实现什么样的逻辑,这取决于你。但是您应该能够在两个级别上考虑它,作为内存中的单个字节,每个字节都有自己的地址,并完全理解您的代码逻辑,它将如何安排这些字节的使用以形成“某些东西的数组”。

通过定义 .bss 扇区,您定义了一个符号/标签 array ,它等于 .bss 段开始的内存地址。然后您保留 200 字节的空间,因此您将添加的任何其他内容(如另一个标签)将从地址 .bss+200 开始。

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

然后

mov dword [array],0x12345678

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

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

当您想将 N 字节 值存储到数组中时,最简单的逻辑是将第一个值存储在地址 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)

IE。对于用户输入 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 <pointer_reg>, <size_of_element> 一样执行 add rdi,96 移动到下一个元素,以避免每次访问的索引值相乘。

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

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

编辑:

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

关于arrays - 将值插入数组并显示,nasm,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47232111/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com