首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >校验位计算德国身份证组件

校验位计算德国身份证组件
EN

Stack Overflow用户
提问于 2020-12-06 08:56:17
回答 1查看 128关注 0票数 1

在昨天我得到了一些答案后,我能够进步一点,但仍然不能弄清楚哪里出了问题,如果这篇文章太多了,很抱歉

我是个编程新手,我必须做以下事情:

写一个程序,让你输入你的身份证号码(它是一个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 (输出))

代码语言:javascript
运行
复制
        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

我非常感谢任何人的帮助,我的思维过程中有一些地方是错误的,但我就是不能弄清楚是什么。

EN

回答 1

Stack Overflow用户

发布于 2020-12-07 07:15:19

您没有正确地恢复堆栈!pop需要以与pushes相反的顺序出现:

代码语言:javascript
运行
复制
checksum:
    push    ebx
    push    esi
    push    edi
    ...
finish:
    pop     edi
    pop     esi
    pop     ebx
    ret

您期望校验和过程在EDX寄存器中返回一个结果,但是您忘记了所有使用mul ebx指令的乘法都将销毁EDX。请记住,产品将出现在组合EDX:EAX中。这是一个可以通过使用imul指令的立即操作数形式解决的问题。

此外,这些mul ebx指令将整个EAXEBX相乘,但是您不能确保EAX的位8..31为零。movzx eax, byte [esi]就可以做到这一点。

下面是我的重写,弥补了上面的问题。我已经改进了您之前的低效分支,但这绝不是唯一(好的)分派解决方案。该过程现在返回EAX寄存器中的结果:

代码语言:javascript
运行
复制
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

下面是使用新过程的结果的方法:

代码语言:javascript
运行
复制
    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

在上面的代码中,我想紧跟您的解决方案。

下面你会找到几个替代的解决方案:

  • 此版本使用3倍的因子展开主循环(从9次迭代到3次迭代)。也许是违反直觉的,但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

  • 此版本使用嵌套循环,并基于这样一个事实,即权重7、3和1可以通过简单的向右移动来生成:

校验和: 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

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65163621

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档