Insert values into array and display, nasm

后端 未结 1 1963
广开言路
广开言路 2021-01-26 12:45

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

相关标签:
1条回答
  • 2021-01-26 13:24

    "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

    0 讨论(0)
提交回复
热议问题