Assembler (NASM Intel x86): String in ASCII umwandeln und rechnen

DeckardCain

Cadet 4th Year
Dabei seit
Jan. 2015
Beiträge
86
Guten Abend!
Ich habe die Aufgabe bekommen im Assembler einen Prüfziffertester für Ausweise zu schreiben.
Man nimmt z.B. die Ausweisnummer 'ABCD12345'. Hierbei stehen die Buchstaben für Zahlen: A=10, B=11, C=12 und so weiter.
ABCD12345
10*7+11*3+12*1+13*7+1*3+2*1+3*7+4*3+5*1=250
Also muss man die einzelnen Ziffern mit 7,3,1,7,3,1,7,3,1 multiplizieren und alle addieren. Die letze Ziffer der Summe ergibt dann die Prüfziffer, in diesem Fall die 0.
Nun würde ich gerne wissen, wie ich es schaffe mit den Buchstaben, die ich auf dem Stack habe zu rechnen. Also den ASCII-Wert so zu verringern, dass ich den tatsächlichen Integer, den ich brauche rausbekomme.
(ASCII-Wert von A -> 65; 65-55 = 10)

Ich hoffe hier gibt es einige Assemblerprogrammierer, die mir da helfen können.


Code:
global main
extern printf
extern atoi

segment .data
    printausweisnummer: db "Ausweisnummer: ",0
    printnr: db "%d", 0
    enter: db "",10,0

segment .text

main:
; print out "Ausweisnummer: <Eingabe>"
    push printausweisnummer
    call printf
    add esp,4

    mov eax, esp       
    add eax, 8
    mov eax, [eax]       
    add eax, 4
    mov eax, [eax]             

    add eax, 9
    mov DWORD [eax],0
    sub eax, 9
    push eax
    call printf
    add esp,4
    push enter
    call printf
    add esp,4
; Ausgabe ende

    mov eax, esp       
    add eax, 8
    mov eax, [eax]       
    add eax, 4
    mov eax, [eax]             
; von hinten anfangen alles zusammenzurechnen
    add eax, 8
    mov DWORD [eax], 0
    sub eax, 1

    push eax
    call atoi
    add esp,4 
    push eax
    push printnr   
    call printf
    add esp,8
; Zahl '4' ausgeben

end:
    push enter
    call printf
    add esp,4
 

blöderidiot

Captain
Dabei seit
Juni 2004
Beiträge
3.368
Ich habe die Aufgabe bekommen im Assembler einen Prüfziffertester für Ausweise zu schreiben.
Boaaahhhhh! Wo bekommt man solche Aufgaben :confused_alt:
Man nimmt z.B. die Ausweisnummer 'ABCD12345'. Hierbei stehen die Buchstaben für Zahlen: A=10, B=11, C=12 und so weiter.
...
Nun würde ich gerne wissen, wie ich es schaffe mit den Buchstaben, die ich auf dem Stack habe zu rechnen. Also den ASCII-Wert so zu verringern, dass ich den tatsächlichen Integer, den ich brauche rausbekomme.
(ASCII-Wert von A -> 65; 65-55 = 10)
Hmm. Welche "Buchstaben, die ich auf dem Stack habe"? Du hast an keiner Stelle irgend einen Buchstaben eingelesen. Außerdem kann Dein Programm so nicht funktionieren. Was soll das Programm eigentlich machen? Das unterscheidet sich ziemlich von der Aufgabenstellung. Aber interessant ist es schon und ich habe vor 20 oder mehr Jahren schon mal in Assembler was gemacht. Daher habe ich Dein Programm minimal verändert und es scheint zu funktionieren. Allerdings von NASM auf MASM (weil mein Visual Studio 2017 MASM eingebaut hat), die Unterschiede sind jedoch gering. Welche Umgebung ist das bei Dir? Windows, Linux?
Anbei das Programm nach meinen Modifikationen.
/edit: ich habe das Programm noch mal komplett durchkommentiert, einen Fehler gefunden und neu eingestellt:
Code:
.586
.model flat 
.data
  szText  db "Ausweisnummer (9 Zeichen): ", 0
  szPrfz  db "Endziffersumme: %d, Pruefziffer: %d", 0Ah, 0
  factor  dd  7,3,1, 7,3,1, 7,3,1 ; Multiplikationstabelle fuer neun Stellen
  sum     dd  0
  
.code
extern _printf:proc
extern _gets:proc
 
main proc C
    enter 0100h, 0        ; Stack: 128 + 64 + 64 bytes =  256 bytes (0100h)
; Stack-layout:
; 0 <- [Eingabepuffer] -| 128(080h) <- [Zeichen-Uebersetzungs-Tb.] -| 256
    lea   esi, [esp]      ; esi zeigt auf Eingabespeicher (Start des Stacks)
    lea   edi, [esp+080h] ; edi zeigt im Stack auf 128+ bytes
    xor   eax, eax        ; eax haelt den Ascii-Zahlenwert
; Erzeuge Zeichen/Buchstaben-Tabelle:
    xor   ebx, ebx        ; Zeichen-Uebersetzungstabelle ab 080h auf Stack
    mov   al, '0'         ; A) Start mit Ascii-Zeichen '0' (eax) auf Pos 0 (ebx)
    mov   ecx, 0ah        ; insg. 10 (0ah) Zahlen: '0', '1', '2' ... '9'
LutNums:                  
    mov   [edi+eax], bl   ; schreibe Zahlenwert (ebx, 0) an Adresse Ascii-Wert (48)
    inc   al              ; auf den Stack und inkrementiere Ascii-Zeichen
    inc   bl              ; und auch Zahlenwert
    loop  LutNums         ; bis cx 10 ... 1
    mov   ecx, 01Ah       ; B) 26 (01Ah) Buchstaben: 'A', 'B', 'C' ... 'Z' 
    mov   al, 'A'         ; Start mit Zeichen 'A' auf naechster Position (ebx, 10) 
LutLett:
    mov   [edi+eax], bl   ; schreibe Zahlenwert (ebx, 10) an Adresse Ascii-Wert (65)
    inc   al              ; auf den Stack und inkrementiere Ascii-Zeichen
    inc   bl              ; und natuerlich Zahlenwert
    loop  LutLett         ; bis cx 26 ... 1 
; Eingabe der Nutzerdaten
    push  offset szText   ; Lade Ausgabetext
    call  _printf         ; Ausgabe - Hinweis
    add   esp, 4          ; setze Stackzeiger zurueck
    push  esi             ; und auf den Stack legen
    call  _gets           ; Eingabe - Daten nach buffer
    add   esp, 4          ; setze Stackzeiger zurueck
; Berechnung der Pruefsummen
    xor   ebx, ebx        ; ebx wird Feld/Tabellenindex
    mov   ecx, 0ah        ; ecx wird Divisor (10) der Produkte fuer Endziffern
Work:         
    mov   al,  [esi+ebx]  ; byte aus Eingabespeicher laden (esi+ebx)
    cmp   al, 'Z'         ; Fehlererkennung: Quick&Dirty Test auf Kleinbuchstaben
    jbe   OK
    and   al, 05Fh        ; Wenn Kleinbuchstaben: konvertiere zu Grossbuchstaben
OK: and   eax, 0FFh       ; al auf volle Registerbreite eax
    mov   al,  [edi+eax]  ; Register zu Offsett in edi -> in Uebersetzungstabelle
    imul  [factor+ebx*4]  ; diesen Wert (jetzt in eax) x Multiplikator aus factor
    idiv  ecx             ; Produkt durch 10 teilen (Endziffer)
    add   [sum], edx      ; Resultat auf Endziffersumme aufrechnen
    inc   ebx             ; Feldindex der 9 Zeichen eins weiter setzen
    cmp   ebx, 09h        ; 1 ... 9 ( 0 ... 8)
    jb    Work
; Ausgabe der Resultate
    xor   edx, edx        ; letzte Ziffer der Endziffersumme bestimmen
    mov   eax, [sum]      ; sum soll durch 10 dividiert werden
    idiv  ecx             ; Rest nach S/10 ist jetzt in edx
    push  edx             ; Pruefziffer  ausgeben
    push  [sum]           ; Summe ausgeben
    push  offset szPrfz   ; String mit Formatierung
    call  _printf 
    add   esp, 0Ch        ; lokalen Stack aufraeumen
; Rueckkehr zum Aufrufer
    xor   eax, eax        ; returnwert: 0
    leave                 ; stackvariablen (256 bytes) entfernen
    ret                   ; zu Aufrufer zurueck
main endp
end
Test:
Ausweisnummer (9 Zeichen): ABCD12345
Endziffersumme: 19, Pruefziffer: 9
 
Zuletzt bearbeitet:
Top