在昨天我得到了一些答案后,我能够进步一点,但仍然不能弄清楚哪里出了问题,如果这篇文章太多了,很抱歉
我是个编程新手,我必须做以下事情:
写一个程序,让你输入你的身份证号码(它是一个9位数的数字,它可以包含字母从A到Z或数字从0到9) (它基于ascii和明显的A=10,B=11等)。
输入位置的权重不同(Pos 1,4,7 =权重7;Pos 2,5,8 =权重3;Pos 3,6,9 =权重1)
因此,每个数字要么乘以7,3,要么1,所有乘积相加,所有乘积和的最后一位是所需的校验位。(这些计算必须在子程序中)
然后,程序应该输出输入数字和末尾的校验位,因此输出应该是10位数字(例如,T22000129 (输入)= T220001293 (输出))
global main
extern printf
section .text
main:
mov eax, [esp+4] ; argc
cmp eax, 2 ; 2 parameters = 1 argument
jne badCommand
mov eax, [esp+8] ; argv
mov eax, [eax+4] ; starting adress string
push eax
call checksum ; calling checksum
xor eax, eax
mov eax, edx
xor edx, edx ; getting the last digit of the value thats saved in edx
mov ebx, 10
div ebx
xor eax, eax
pop eax
;; output ID Card number (input) + checkdigit ;;
push edx ; check digit
push eax ; string - ID-card-number
push stringFormat
call printf
add esp, 12 ; esp 3DWORD
ret ; end main
;; subprogram ;;
checksum:
push ebx
push esi ; Call-Saved Register - safe before use
push edi
mov esi, [esp+16] ; String-Adresse - get the parameter
mov edi, 9 ; jump counter
start:
xor ebx, ebx
cmp edi, 0
je finish
mov al, [esi]
cmp al, 65
jge letterweight
jl numberweight
letterweight:
cmp edi, 9
je letterseven
cmp edi, 8
je letterthree
cmp edi, 7
je letterone
cmp edi, 6
je letterseven
cmp edi, 5
je letterthree
cmp edi, 4
je letterone
cmp edi, 3
je letterseven
cmp edi, 2
je letterthree
cmp edi, 1
je letterone
numberweight:
cmp edi, 9
je numberseven
cmp edi, 8
je numberthree
cmp edi, 7
je numberone
cmp edi, 6
je numberseven
cmp edi, 5
je numberthree
cmp edi, 4
je numberone
cmp edi, 3
je numberseven
cmp edi, 2
je numberthree
cmp edi, 1
je numberone
letterseven:
sub al, 55
mov ebx, 7
mul ebx
mov ecx, eax
add edx, ecx
jmp ediesi
numberseven:
mov ebx, 7
mul ebx
mov ecx, eax
add edx, ecx
jmp ediesi
letterthree:
sub al, 55
mov ebx, 3
mul ebx
mov ecx, eax
add edx, ecx
jmp ediesi
numberthree:
mov ebx, 3
mul ebx
mov ecx, eax
add edx, ecx
jmp ediesi
letterone:
sub al, 55
mov ebx, 1
mul ebx
mov ecx, eax
add edx, ecx
jmp ediesi
numberone:
mov ebx, 1
mul ebx
mov ecx, eax
add edx, ecx
jmp ediesi
ediesi:
dec edi
inc esi
jmp start
finish:
pop ebx
pop esi ; Call-Saved Register - pop after use
pop edi
ret
badCommand:
push badArgumentFormat
call printf
add esp, 4 ; esp 1DWORD
ret
section .data
badArgumentFormat:
db 'bad argument', 10, 0 ; 10 = LF
stringFormat:
db '"%s%1d"', 10, 0
我知道这可能不是最好的方式,但它确实做了它应该做的事情,但它也不是。
我的思维过程可能是:
main函数将输入加载到eax中,以便稍后可以将其作为输出的第一部分
推送eax,这样我就可以使用它调用子程序进行计算
子程序:在使用子程序之前推送调用保存的寄存器
将输入移动到esi,这样我就可以使用它将edi设置为9,这样我就可以将它用作跳转计数器
将ebx设置为0,这样我就可以将edi与0进行比较,如果这是case程序结束的话。
然后,我将输入的第一个数字移动到al中,将其与65进行比较,因为在ascii中,因为A=65是第一个字母
跳转到权重确定以便我知道乘数是多少一旦我弄清楚乘数是什么,它就会跳到字母或数字计算方案中。
如果它是一个字母,它执行以下操作:从我存储在al中的输入数字的值中减去55 (这样做是因为如果它跳到字母,则该值必须至少为65,因此减去55将得到字母的值(A=65-55 = 10) )
然后,每次我都将乘法器移到ebx中,这样我就可以将eax与ebx相乘,然后将eax存储到ecx中,然后将ecx添加到edx中
在这之后,我跳转到dec跳跃计数器(edi)和inc esi,所以它给我输入的第二个数字的值
我一直这样做,直到我的edi为0,之后我返回到主程序
以xor eax开头和结尾的部分,eax给出了乘积和的最后一位数。
在此之后,我弹出eax以获取我的输入
打印eax和edx
我很抱歉写了这么长的文章,但由于某些原因,我不知道为什么我的结果是错误的。
使用上面的代码对我的校验数字的输出是:第一次运行程序,第二次运行它的T220001297 : T220001297第三次: T220001291第四次: T220001291第五次: T220001299
我非常感谢任何人的帮助,我的思维过程中有一些地方是错误的,但我就是不能弄清楚是什么。
发布于 2020-12-07 07:15:19
您没有正确地恢复堆栈!pop
需要以与push
es相反的顺序出现:
checksum:
push ebx
push esi
push edi
...
finish:
pop edi
pop esi
pop ebx
ret
您期望校验和过程在EDX
寄存器中返回一个结果,但是您忘记了所有使用mul ebx
指令的乘法都将销毁EDX
。请记住,产品将出现在组合EDX:EAX
中。这是一个可以通过使用imul
指令的立即操作数形式解决的问题。
此外,这些mul ebx
指令将整个EAX
与EBX
相乘,但是您不能确保EAX
的位8..31为零。movzx eax, byte [esi]
就可以做到这一点。
下面是我的重写,弥补了上面的问题。我已经改进了您之前的低效分支,但这绝不是唯一(好的)分派解决方案。该过程现在返回EAX
寄存器中的结果:
checksum:
push ebx
push esi
push edi
mov esi, [esp+16]
mov edi, 9
xor eax, eax ; EAX will be result
start:
movzx ebx, byte [esi] ; Expected [0,9] and [A,Z]
cmp bl, 65
jb numberweight
letterweight:
sub ebx, 55
numberweight:
cmp edi, 7
je one
cmp edi, 4
je one
cmp edi, 1
je one
cmp edi, 8
je three
cmp edi, 5
je three
cmp edi, 2
je three
; Here EDI just has got to be 9, 6, or 3!
; Therefore no need to compare and just fall through
seven:
imul ebx, 7 ; See below for an alternative (possible optimization)
jmp addit
three:
imul ebx, 3 ; See below for an optimization
;;jmp addit ; No longer needed if we drop the 'one' code.
one:
;;imul ebx, 1 ; Keeping this would be silly.
addit:
add eax, ebx
inc esi
dec edi
jnz start
finish:
pop edi
pop esi
pop ebx
ret
下面是使用新过程的结果的方法:
call checksum ; -> EAX
; getting the last digit of the value that's saved in EAX
xor edx, edx
mov ebx, 10
div ebx ; EDX:EAX / 10 -> EDX = [0,9], don't care about EAX
在上面的代码中,我想紧跟您的解决方案。
下面你会找到几个替代的解决方案:
call .FetchDigit
(相对于内联它)并不一定会使速度变慢:校验和: push esi push edi mov esi,esp+16 mov edi,3xor eax,eax;EAX将是结果.start: call .FetchDigit;-> EDX=0,35 ESI++ imul edx,7;\ EQV to 'lea eax,eax+edx*8‘'sub eax,edx’add eax,edx;/ call .FetchDigit;-> EDX=0,35 ESI++ lea edx,edx+edx*2;Faster then 'imul edx,3‘add eax,edx call .FetchDigit;-> EDX=0,35 ESI++ ;;imul edx,1 add eax,edx dec jnz .start pop edi pop esi ret;--- .FetchDigit: movzx edx,byte esi;应为0,9和A,Z cmp dl,65 jb .numberweight .letterweight: sub,55 .numberweight: ret
校验和: push esi push edi mov esi,esp+16 mov edi,3xor eax,EAX;eax将为结果.OuterLoop: mov ecx,7 .InnerLoop: movzx edx,byte esi;预期为0,9和A,Z cmp dl,65 jb .numberweight .letterweight: sub,55 .numberweight: imul edx,ecx;ECX={7,3,1}添加eax,edx shr ecx,1 jnz .InnerLoop dec edi jnz .OuterLoop pop edi pop esi ret
https://stackoverflow.com/questions/65163621
复制相似问题