如何在汇编语言中使用 long int 和 long int 数组

问题描述 投票:0回答:1

我写了一个程序,用一个 long int 和一个 int 数组做除法和模运算。当我想写我的除法运算结果但我不能。我无法找出问题所在,但我认为我错误地使用了数据部分的寄存器分配过程。请帮我。我认为我在数据部分错误地调用了 array 和 int array,或者我在使用寄存器时遇到了问题。这是我的代码:

         global    _start

          section   .text
_start:   
          
          mov r9, number        ; rdi stores adress of number array
          mov r12,  0             ; get number of k for determine index of number array
     
          
     L3:                       ;  function begin
     
          mov r15,  0                    ; get number of i because using i of loop register
          mov r14, [digits]          ; get number of digits
          mov r13, [r9 + r12*4]      ; get array number for using array adress. We use 4*k because we take k. index of array     
          
      
          syscall
          cmp r13,  0          ; determine number is negative or positive
          jl  L2               ; if it is negative we goto else part for print minus
          
          ; print blank         otherwise we print blank 
          mov rax, 1
          mov rdi, 1
          mov rsi, blank
          mov rdx, 1
          syscall
          
          jmp L1               ; after printing, jump L1 statement
  
     L2:                       ; if number is negative continiuos here so Else part  
          ; print minus
          mov rax, 1
          mov rdi, 1
          mov rsi, minus
          mov rdx, 1
          syscall   
          
          neg r13              ; convert the negative number to positive number      
      
     L1:                        ; into the loop     
           
          ; division operation  digit = (number/digits)
          mov rax, r13         ; dividend
          cqo
          mov rbx, r14         ; divisor
          idiv rbx              ; after the div operation rbx store division
          mov r10, rax         ; result is egual digit (r10)
         
          
          ; print digit
          add rsp , 8 
          add r10, 48  
          mov rax , 1 
          mov rdi, 1
          push r10
          mov rsi, rsp 
          mov rdx, 1
          syscall
      
          ; mod operation   number = number % digits
          mov rax, r13         ; dividend
          cqo
          mov rbx, r14         ; divisor
          xor rdx, rdx         ; rdx which store reminder be zero
          idiv rbx              ; after the div operation rbx store division    
          mov r13, rdx         ; rdx store reminder and reminder egual number
 
          ; division operation  digits = (digits/10)
          mov rdx, 1
          mov rax, r14         ; dividend
          mov rbx, 10          ; divisor
          div rbx              ; after the div operation rbx store division
          mov r14, rbx         ; result is egual digit (r14)   
   
          inc r15              ; increment the loop register
        
          cmp r15, 9           ; compare loop register with 9 so loop work 8 times
          jl  L1               ; if loop register less than 9 return loop
          
          ; print new line  
          mov rax, 1
          mov rdi, 1
          mov rsi, newline
          mov rdx, 1
          syscall  
          
        
          inc r12            ; increment k by 1  
          

          cmp r12, 8         ; compare k with numberCount
          jl L3              ; if k less than numberCount, goto L3 that is begining write9digits function 
         
         
     Exit:                                  ; if array index(k) greater than numberCount work Exit
          mov       rax, 60                 ; system call for exit
          xor       rdi, rdi                ; exit code 0
          syscall                           ; invoke operating system to exit

          section   .data
newline      db       10      ; note the newline at the end
blank        db       ' '
minus        db       '-'
i            dd       0      
k            dd       0      
digits       dd       100000000
number       dd       321762410, 9, 2943018, 0, 19372039, 18, -76241, -208424 

这段代码将打印这个

  00000000

  0�0000000

  0�0000000

  0�0000000

  000000000

-0�0000000

-0�0000000

  0_0000000

但是根据我的 C 代码结果必须是这样的:

 321762410
 000000009
 002943018
 000000000
 019371039
 000000018
-000076241
-000208424

我尝试使用 qword 转换取整数但没有任何改变。在我将整数格式更改为十六进制格式后,没有任何改变。最后,我尝试更改 [digits] 和 [r9 + r12*4]。

          mov r14, [digits]          ; get number of digits
          mov r13, [r9 + r12*4]      ; get array number for using array adress. We use 4*k 

如果我将 [digits] 更改为 5 并将 [r9 + r12*4] 更改为 21,我将得到以下输出:

          mov r14, 5       ; get number of digits
          mov r13, 21      ; get array number for using array adress. We use 4*k 
  400000000

  400000000

  400000000

  400000000

  400000000

  400000000

  400000000

  400000000
assembly x86-64
1个回答
0
投票

问题揭秘审查

mov r9, number        ; rdi stores adress of number array

R9 与 RDI 不同。更改评论。

mov r14, [digits]     ; get number of digits

这里加载的是除数的初始值(100,000,000)。并且 digits 被定义为一个双字,因此加载这个值需要写

mov r14d, [digits]
movzx r14, dword [digits]
.

mov r13, [r9 + r12*4] ; get array number for using array adress. We use 4*k because we take k. index of array

数组元素是双字,所以 *4 比例因子很好,但是 R9 是一个 qword 寄存器,所以你应该加载带有符号扩展的值:

movsx r13, dword [r9 + r12 * 4]

或者,您可以将数组元素定义为 qwords,然后编写:

mov   r13, [r9 + r12 * 8]
syscall

你有一个冗余的 SYSCALL 指令。将被删除。

处理负输入的代码如果写成这样会更好看:

    mov  rsi, blank
    test r13, r13      ; determine number is negative or positive
    jns  IsPos         ; if it is positive we print BLANK
    mov  rsi, minus    ; else we print MINUS
    neg  r13           ; convert the negative number to positive number      
IsPos:          
    mov rax, 1
    mov rdi, 1
    mov rdx, 1
    syscall
L1:
mov  rbx, r14         ; divisor
idiv rbx              ; after the div operation rbx store division

首先将除数从 R14 移动到 RBX 没有任何好处。你可以简单地写:

idiv  r14
.

; print digit
add rsp , 8 

print digit中,存在

add rsp, 8
操作以从堆栈中删除
push r10
值。显然,您只能在推送执行后执行此操作。

; print digit
add  r10, 48  
mov  rax, 1 
mov  rdi, 1
push r10         ; (1)
mov  rsi, rsp 
mov  rdx, 1
syscall
add  rsp, 8      ; (1)
; mod operation   number = number % digits
mov rax, r13         ; dividend
cqo
mov rbx, r14         ; divisor
xor rdx, rdx         ; rdx which store reminder be zero
idiv rbx             ; after the div operation rbx store division    

mod操作中,

xor rdx, rdx
破坏了执行
cqo
的努力,这在使用
idiv
之前是正常的。您 can 使用
xor rdx, rdx
但与
div
(无符号除法)结合使用。

; division operation  digits = (digits/10)
mov rdx, 1
mov rax, r14         ; dividend
mov rbx, 10          ; divisor
div rbx              ; after the div operation rbx store division
mov r14, rbx         ; result is egual digit (r14)   

在将除数减少 10 倍的部分中,您引入了将 RDX 设置为 1 的错误,在使用

div
之前应该将其归零。此外,除法的商在 RAX 中,因此将其移至 R14。

改进代码

代码不是最优的。使用收缩除数的数字转换比使用固定除数 10 并向后存储更昂贵。

         global    _start

         section   .text
_start:   
          
    mov r9, number     ; address of number array
    mov r12, 0         ; get number of k for determine index of number array
L3:                    ;  function begin
     
    mov r15, 0              ; get number of i because using i of loop register
    mov r14, [divisor]      ; get initial DIVISOR
    mov r13, [r9 + r12 * 8] ; get array number for using array address. We use 8*k because we take k. index of array     

    mov  rsi, blank
    test r13, r13      ; determine number is negative or positive
    jns  IsPos         ; if it is positive we print BLANK
    mov  rsi, minus    ; else we print MINUS
    neg  r13           ; convert the negative number to positive number      
IsPos:          
    mov rax, 1
    mov rdi, 1
    mov rdx, 1
    syscall
L1:
    ; division operation  digit = (number/digits)
    mov rax, r13         ; dividend
    cqo
    idiv r14
    mov  r10, rax        ; result is equal digit (r10)

    ; print digit
    add  r10, 48  
    mov  rax, 1 
    mov  rdi, 1
    push r10             ; (1)
    mov  rsi, rsp 
    mov  rdx, 1
    syscall
    add  rsp, 8          ; (1)
    
    ; mod operation   number = number % digits
    mov  rax, r13        ; dividend
    cqo
    idiv r14
    mov  r13, rdx        ; rdx store remainder and remainder equal number
 
    ; division operation  digits = (digits/10)
    mov  rax, r14        ; dividend
    xor  edx, edx        ; Equivalent and better than `mov rdx, 0`
    mov  rbx, 10         ; divisor
    div  rbx
    mov  r14, rax
    
    inc  r15             ; increment the loop register
    cmp  r15, 9          ; compare loop register with 9 so loop work 8 times
    jb   L1              ; if loop register less than 9 return loop
          
    ; print new line  
    mov  rax, 1
    mov  rdi, 1
    mov  rsi, newline
    mov  rdx, 1
    syscall  
          
    inc  r12            ; increment k by 1  
    cmp  r12, 8         ; compare k with numberCount
    jb   L3             ; if k less than numberCount, goto L3 that is beginning write9digits function 
         
         
Exit:                   ; if array index(k) greater than numberCount work Exit
    mov  rax, 60        ; system call for exit
    xor  rdi, rdi       ; exit code 0
    syscall             ; invoke operating system to exit

          section   .data
newline      db       10      ; note the newline at the end
blank        db       ' '
minus        db       '-'
i            dq       0      
k            dq       0      
divisor      dq       100000000
number       dq       321762410, 9, 2943018, 0, 19372039, 18, -76241, -208424 
© www.soinside.com 2019 - 2024. All rights reserved.