「陣列」, 「載體」,等等......所有這些都是更高層次的概念。該機器具有可通過單字節尋址的存儲器,以及您使用代碼實現的邏輯類型,這取決於您。但是你應該能夠在兩個層面上思考它,就像內存中的單個字節一樣,每個字節都有自己的地址,並且完全理解你的代碼邏輯,它將如何安排那些字節的使用以形成「一些東西」。
隨着您對.bss
扇區的定義,您可以定義一個符號/標籤array
,它等於.bss
段開始的內存地址。然後你保留200字節的空間,所以你將添加的任何其他內容(如另一個標籤)將從地址.bss+200
開始。
假設(例如)將二進制文件加載到內存並跳轉到入口點後,.bss位於地址0x1000
。
然後
mov dword [array],0x12345678
將存儲4個字節到內存地址0x1000 .. 0x1003
,與具有值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
可以用來存儲第一個值。但是這不是很實用,如果你正在閱讀某種循環的輸入。比方說,你想閱讀的用戶,或價值99
最多200個值會結束得越早,那麼你可以通過註冊使用索引,如:
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
...
對於字/雙字/四字元件陣列的x86內存操作數比例係數,這樣你就可以使用索引值會通過+1和地址ESS值等:
mov [array+4*rsi],eax ; store dword value into "array[rsi]"
對於其他尺寸元素它通常是更有效的具有指針,而不是索引,並且通過這樣做add <pointer_reg>, <size_of_element>
像add rdi,96
移動到下一個元素,以避免索引值的乘法對每個訪問。
etc ...讀取值返回的方式是相同的,但是顛倒了操作數。
順便說一句,這些例子並沒有像「覆蓋」它那麼多的「插入」值到數組中。計算機的內存已經存在,並且有一些值(.bss
被libc或OS IIRC歸零?否則就會出現一些垃圾),所以它只是用來自用戶的值覆蓋舊的垃圾值。在resb
中,仍有200字節的內存「保留」,並且您的代碼必須記錄實際大小(輸入值的計數),以瞭解用戶輸入結束的位置以及垃圾數據的起始位置(或者您最終可以編寫值99
並將其用作「終止符」值,那麼只需要數組的地址來掃描它的內容,並在找到值99
時停止)。
編輯:
以防萬一你仍然不知道爲什麼我有時會用方括號,有時沒有,這Q +一個看起來很詳細,YASM語法相同NASM括號用法:Basic use of immediates (square brackets) in x86 Assembly and yasm
與'digito_um'一樣是'digit_one'嗎?你是否在同一個地方有兩個標籤,或者只有一半標籤翻譯成英文?如果它們不在同一地點,那麼'sub'指令與乘法無關。 –
當你說「插入」時,你的意思是你想複製一個以後的所有元素(比如[C++'std :: vector :: insert'](http://en.cppreference.com/w/cpp /容器/載體/插入)),或者你想覆蓋一個元素,如正常的數組元素分配?或者你的意思是一個SIMD向量(像'xmm0',使用'pinsrb xmm0,eax,5'來替換'xmm0'的字節5'al')? –
什麼是目標平臺... Ubuntu的? 32或64位二進制? – Ped7g