Insert values into array and display, nasm

元气小坏坏 提交于 2019-12-31 05:27:14

问题


First of all, this is a homework assignment.

I have a loop to get values of two digits individually, and joining them by doing a multiplication of the first digit by 10 and adding with the second digit to get an integer.

I'm doing all this and saving in my AL register, and now I want to insert that integer into an array and then scan that array and display those numbers.

How can I insert into vector and read from vector?

My array:

section .bss
    array resb 200  

My digit convert:

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

回答1:


"arrays", "vectors", etc... all that is higher level concept. The machine has memory, which is addressable by single byte, and what kind of logic you implement with your code, that's up to you. But you should be able to think about it on both levels, as single bytes in memory, each having it's own address, and fully understand your code logic, how it will arrange usage of those bytes to form "array of something".

With your definition of .bss sector you define one symbol/label array, which is equal to the address into memory where the .bss segment starts. Then you reserve 200 bytes of space, so anything else you will add after (like another label) will start at address .bss+200.

Let's say (for example) after loading your binary into memory and jumping to entry point, the .bss is at address 0x1000.

Then

mov dword [array],0x12345678

will store 4 bytes into memory at addresses 0x1000 .. 0x1003, with particular bytes having values 78 56 34 12 (little-endian break down of that dword value).

If you will do mov dword [array+199],0x12345678, you will write value 0x78 into the last officially reserved byte by that resb 200, and remaining 3 bytes will overwrite the memory at addresses .bss+200, .bss+201 and .bss+202 (probably damaging some other data, if you will put something there, or crashing your application, if it will cross the memory page boundary, and you are at the end of available memory for your process).

As you want to store N byte values into array, the simplest logic is to store first value at address array+0, second at array+1, etc... (for dword values the most logical way is array+0, array+4, array+8, ....).

i.e. mov [array+0],al can be used to store first value. But that's not very practical, if you are reading the input in some kind of loop. Let's say you want to read at most 200 values from user, or value 99 will end sooner, then you can use indexing by register, like:

    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)

I.e. for user input 32, 72, 13, 0, 16, 99 the memory at address 0x1000 will have 5 bytes modified, containing (in hexa) now: 20 48 0D 00 10 ?? ?? ?? ....

If you are somewhat skilled asm programmer, you will not only index by register, but also avoid the hardcoded array label, so you would probably do an subroutine which takes as argument target address (of array), and maximum count:

; 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

Then you can call that subroutine from main code like this:

    ...
    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
    ...

For word/dword/qword element arrays the x86 has scaling factor in memory operand, so you can use index value going by +1, and address value like:

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

For other sized elements it's usually more efficient to have pointer instead of index, and move to next element by doing add <pointer_reg>, <size_of_element> like add rdi,96, to avoid multiplication of index value for each access.

etc... reading values back is working in the same way, but reversed operands.

btw, these example don't as much "insert" values into array, as "overwrite" it. The computer memory already exists there and has some values (.bss gets zeroed by libc or OS IIRC? Otherwise some garbage may be there), so it's just overwriting old junk values with the values from user. There's still 200 bytes of memory "reserved" by resb, and your code must keep track of real size (count of inputted values) to know, where the user input ends, and where garbage data starts (or you may eventually write the 99 value into array too, and use that as "terminator" value, then you need only address of array to scan it content, and stop when value 99 is found).

EDIT:

And just in case you are still wondering why I am sometimes using square brackets and sometimes not, this Q+A looks detailed enough and YASM syntax is same as NASM in brackets usage: Basic use of immediates (square brackets) in x86 Assembly and yasm



来源:https://stackoverflow.com/questions/47232111/insert-values-into-array-and-display-nasm

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!