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

ukxgm1gy  于 2023-04-21  发布在  其他
关注(0)|答案(1)|浏览(121)

我写了一个程序,用一个long int和一个int数组做除法和mod运算。当我想写我的除法运算的结果,但我不能。我不能找出问题,但我认为我使用了错误的数据部分的寄存器分配过程。请帮助我。我认为我从数据部分调用数组和int数组错误,或者我有问题与寄存器使用。这是我的代码:

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转换take integer,但没有任何变化。在我将整数的格式更改为十六进制格式后,没有任何变化。最后,我尝试更改[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
whitzsjs

whitzsjs1#

问题揭示审核

mov r9, number        ; rdi stores adress of number array

R9和RDI不一样。修改注解。R9不是被call-clobbered了吗?(请看我下面的改进代码,它没有使用R9)

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值从堆栈中删除。显然,您只能在push执行后执行此操作。

; 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之前是正常的。您可以 * 使用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:   
          
    xor  r12d, r12d    ; get number of k for determine index of number array
L3:                    ;  function begin
     
    xor  r15d, r15d    ; get number of i
    mov  r14, [divisor]          ; get initial DIVISOR
    mov  r13, [number + 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

相关问题