Cooler_

telnet, intel ASM

Sep 8th, 2012
218
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ; Telnet written in 32-bit x86 assembly, using Linux system calls only
  2. ;
  3. ; Assemble and link with
  4. ;  nasm -f elf telnet.asm -o telnet.o
  5. ;  ld -s telnet.o -o telnet
  6. ;
  7. ; Tested on i686 Linux, kernel version 2.6.27
  8. ;
  9. ; Usage: ./telnet <IP address> <port>
  10. ; Note: host name resolution is not implemeneted. This version only takes IP
  11. ; addresses.
  12. ;
  13. ; Star Wars Telnet Demo
  14. ; towel.blinkenlights.nl -> 94.142.241.111
  15. ; Run:
  16. ; $ ./telnet 94.142.241.111 23
  17.  
  18. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  19. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  20. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  21.  
  22. section .data
  23.     msgInvalidArguments:    db 'Invalid IP address or port supplied!',10,0
  24.     msgInvalidArgumentsLen: equ $-msgInvalidArguments
  25.  
  26.     msgErrorSocket:     db 'Error creating socket!',10,0
  27.     msgErrorSocketLen:  equ $-msgErrorSocket
  28.  
  29.     msgErrorConnect:    db 'Error connecting to server!',10,0
  30.     msgErrorConnectLen: equ $-msgErrorConnect
  31.  
  32.     msgErrorSelect:     db 'Error with select()!',10,0
  33.     msgErrorSelectLen:  equ $-msgErrorSelect
  34.  
  35.     msgUsage:       db 'Usage: ./telnet <IP address> <port>',10,0
  36.     msgUsageLen:        equ $-msgUsage
  37.  
  38.     ; Arguments for socket(): socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  39.     socketArgs:     dd 2,1,6
  40.  
  41. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  42. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  43. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  44.  
  45. section .bss
  46.     ; Socket file descriptor returned by socket()
  47.     sockfd:         resd    1
  48.  
  49.     ; Storage for the 4 IP octets
  50.     ipOctets        resb    4
  51.  
  52.     ; Storage for the connection port represented in one 16-bit word
  53.     ipPort          resw    1
  54.  
  55.     ; Arguments for connect():
  56.     ;   connect(sockfd, serverSockaddr, serversockaddrLen);
  57.     connectArgs     resd    3
  58.  
  59.     ; The read file descriptor array for select()
  60.     masterReadFdArray   resb    128
  61.     checkReadFdArray    resb    128
  62.     readFdArrayLen      equ 128
  63.  
  64.     ; sockaddr_in structure that needs to be filled in for the
  65.     ; connect() system call.
  66.     ;   struct sockaddr_in {
  67.     ;       short            sin_family;
  68.         ;       unsigned short   sin_port;
  69.         ;       struct in_addr   sin_addr;
  70.         ;       char             sin_zero[8];
  71.     ;   };
  72.     serverSockaddr      resb    (2+2+4+8)
  73.     serverSockaddrLen   equ 16
  74.  
  75.     ; Read buffer for reading from stdin and the socket
  76.     readBuffer      resb    1024
  77.     readBufferLen       resd    1
  78.     readBufferMaxLen    equ 1024
  79.  
  80. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  81. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  82. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  83.  
  84. section .text
  85.     global _start
  86.  
  87. _start:
  88.     ; Pop argc
  89.     pop eax
  90.    
  91.     ; Check if we have the correct number of arguments (2), for the
  92.     ; program name and IP address.
  93.     cmp eax, 3 
  94.     je parse_program_arguments
  95.    
  96.     ; Otherwise, print the usage and quit.
  97.     push msgUsage
  98.     push msgUsageLen
  99.     call cWriteString
  100.     add esp, 8
  101.     call cExit
  102.  
  103. parse_program_arguments:
  104.     ; Set the direction flag to increment, so edi/esi are INCREMENTED
  105.     ; with their respective load/store instructions.
  106.     cld
  107.  
  108.     ; Pop the program name string
  109.     pop eax
  110.  
  111.     ;;; Convert the port and IP address strings to numbers ;;;
  112.  
  113.     ; Next on the stack is the IP address
  114.     ; Convert the IP address string to four byte sized octets.
  115.     call cStrIP_to_Octets
  116.     add esp, 4
  117.     ; Check for errors
  118.     cmp eax, 0
  119.     jl invalid_program_arguments
  120.  
  121.     ; Next on the stack is the port
  122.     ; Convert the port string to a 16-bit word.
  123.     call cStrtoul
  124.     add esp, 4
  125.     mov [ipPort], eax
  126.     ; Check for errors
  127.     cmp eax, 0
  128.     jge network_open_socket
  129.  
  130.     ; Otherwise, print error for invalid arguments and quit.
  131.     invalid_program_arguments:
  132.     push msgInvalidArguments
  133.     push msgInvalidArgumentsLen
  134.     call cWriteString
  135.     add esp, 8
  136.     call cExit
  137.  
  138. network_open_socket:
  139.     ;;; Open a socket and store it in sockfd ;;;
  140.  
  141.     ; Syscall socketcall(1, ...); for socket();
  142.     mov eax, 102
  143.     mov ebx, 1
  144.     mov ecx, socketArgs
  145.     int 0x80
  146.  
  147.     ; Copy our socket file descriptor to our variable sockfd
  148.     mov [sockfd], eax
  149.  
  150.     ; Check if socket() returned a valid socket file descriptor
  151.     cmp eax, 0
  152.     jge network_connect
  153.  
  154.     ; Otherwise, print error creating socket and quit.
  155.     push msgErrorSocket
  156.     push msgErrorSocketLen
  157.     call cWriteString
  158.     add esp, 8
  159.     call cExit
  160.    
  161. network_connect:
  162.     ;;; Setup the argument to connect() and call connect() ;;;
  163.    
  164.     ; Fill in the sockaddr_in structure with the
  165.     ; network family, port, and IP address information,
  166.     ; along with the zeros in the zero field.
  167.     mov edi, serverSockaddr
  168.  
  169.     ; Store the network family, AF_INET = 2
  170.     mov al, 2
  171.     stosb
  172.     mov al, 0
  173.     stosb
  174.  
  175.     ; Store the port, in network byte order (big endian).
  176.    
  177.     ; High byte first
  178.     mov ax, [ipPort]
  179.     ; Truncate the lower byte
  180.     shr ax, 8
  181.     stosb
  182.  
  183.     ; Low byte second
  184.     mov ax, [ipPort]
  185.     stosb
  186.  
  187.     ; Store the 4 octets of the IP address, reading from the
  188.     ; ipOctets 4-byte array and copying to the respective
  189.     ; locations in the serverSockaddr structure.
  190.     mov esi, ipOctets
  191.     ; movsb * 4 = movsd
  192.     movsd
  193.  
  194.     ; Zero out the remaining 8 bytes of the structure
  195.     mov al, 0
  196.     mov ecx, 8
  197.     rep stosb
  198.  
  199.     ; Setup the array that will hold the arguments for connect
  200.     ; we are passing through the socketcall() system call.
  201.     mov edi, connectArgs
  202.     ; sockfd
  203.     mov eax, [sockfd]
  204.     stosd
  205.     ; Pointer to serverSockaddr structure
  206.     mov eax, serverSockaddr
  207.     stosd
  208.     ; serverSockaddrlen
  209.     mov eax, serverSockaddrLen
  210.     stosd
  211.    
  212.     ; Syscall socketcall(3, ...); for connect();
  213.     mov eax, 102
  214.     mov ebx, 3
  215.     mov ecx, connectArgs
  216.     int 0x80
  217.    
  218.     ; Check if connect() returned a success
  219.     cmp eax, 0
  220.     jge network_setup_file_descriptors
  221.  
  222.     ; Otherwise, print error creating socket and quit.
  223.     push msgErrorConnect
  224.     push msgErrorConnectLen
  225.     call cWriteString
  226.     add esp, 8
  227.     jmp network_premature_exit
  228.  
  229. network_setup_file_descriptors:
  230.     ;;; Clear the read fd array, add stdin and the socket fd to the
  231.     ;;; array. ;;;
  232.  
  233.     ; Point edi to the beginning of the read file descriptor array
  234.     mov edi, masterReadFdArray
  235.    
  236.     ; Zero out all 128 bytes of the read file descriptor array
  237.     mov al, 0
  238.     mov ecx, readFdArrayLen
  239.     rep stosb
  240.  
  241.     ; Add stdin, file descriptor 0, to the read file descriptor array
  242.     mov edi, masterReadFdArray
  243.     mov al, 1
  244.     stosb
  245.  
  246.     ; Reset edi to the beginning of the read file descriptor array
  247.     mov edi, masterReadFdArray
  248.     ; Copy the value of the socket file descriptor to eax
  249.     mov eax, [sockfd]
  250.    
  251.     ; Divide eax by 8, so we can find the offset from the beginning of
  252.     ; the file descriptor array, so we can set the necessary bit for
  253.     ; the socket file descriptor in the read file descriptor array.
  254.     shr eax, 3
  255.     ; Increment the pointer by the offset
  256.     add edi, eax
  257.  
  258.     ; Make another copy of the socket file descriptor in ecx
  259.     mov ecx, [sockfd]
  260.     ; Isolate the bit offset
  261.     and cl, 0x7
  262.     ; Left shift a 1 to make a bit mask at that bit offset
  263.     mov al, 1
  264.     shl al, cl
  265.     ; Bitwise OR the bit high at correct bit position in the array
  266.     or [edi], al
  267.  
  268. network_read_write_loop:
  269.     ; Copy over the master read file descriptor array to the
  270.     ; checking read file descriptor array, which we will pass
  271.     ; to select and check which file descriptors are set/unset.
  272.     mov edi, checkReadFdArray
  273.     mov esi, masterReadFdArray
  274.     mov ecx, readFdArrayLen
  275.     rep movsb
  276.  
  277.     ; Syscall select(sockfd+1, readFdArray, 0, 0, 0);
  278.     ; nfds, the first argument of select, is the highest
  279.     ; file descriptor + 1, in our case it would be sockfd+1,
  280.     ; since stdin is always file descriptor 0.
  281.     mov eax, 142
  282.     mov ebx, [sockfd]
  283.     inc ebx
  284.     mov ecx, checkReadFdArray
  285.     mov edx, 0
  286.     mov esi, 0
  287.     mov edi, 0
  288.     int 0x80
  289.  
  290.     ; Check the return value of select for errors
  291.     cmp eax, 0
  292.  
  293.     jg check_read_file_descriptors
  294.     ; Otherwise, print error calling select and quit
  295.     push msgErrorSelect
  296.     push msgErrorSelectLen
  297.     call cWriteString
  298.     add esp, 8
  299.     jmp network_premature_exit
  300.    
  301.     check_read_file_descriptors:
  302.     check_stdin_file_descriptor:
  303.         ;;; Check if the stdin file descriptor is set ;;;
  304.  
  305.         ; Read the first byte (where the first bit, stdin, will be
  306.         ; located) of the updated file descriptor array
  307.         mov esi, checkReadFdArray
  308.         lodsb
  309.         ; Mask the first bit in the array
  310.         and al, 0x01
  311.         ; Check if it is set
  312.         cmp al, 0x01
  313.         jne check_socket_file_descriptor
  314.         ; Otherwise, it is set, and we need to read the data into a
  315.         ; buffer, and then write it to the socket
  316.         call cReadStdin
  317.         call cWriteSocket
  318.    
  319.     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  320.  
  321.     check_socket_file_descriptor:
  322.         ;;; Check if the socket file descriptor is set ;;;
  323.  
  324.         ; Reset esi to the beginning of the read file descriptor array
  325.         mov esi, checkReadFdArray
  326.         ; Copy the value of the socket file descriptor to eax
  327.         mov edx, 0
  328.         mov eax, [sockfd]
  329.  
  330.         ; Divide eax by 8, so we can find the offset from the beginning
  331.         ; of the file descriptor array, so we can set the necessary bit
  332.         ; for the socket file descriptor in the read file descriptor
  333.         ; array.
  334.         shr eax, 3
  335.         ; Increment the pointer by the offset
  336.         add esi, eax
  337.  
  338.         ; Make another copy of the socket file descriptor in ecx
  339.         mov ecx, [sockfd]
  340.         ; Isolate the bit offset
  341.         and cl, 0x7
  342.         ; Left shift a 1 to make a bit mask at that bit offset
  343.         mov bl, 1
  344.         shl bl, cl
  345.    
  346.         ; Read the byte and mask the correct bit for the socket fd
  347.         lodsb
  348.         and al, bl
  349.         ; Check if it is set
  350.         cmp al, bl
  351.         jne check_socket_file_descriptor_done
  352.         ; Otherwise, it is set, and we need to read the data into a
  353.         ; buffer, and then write it to stdout
  354.         call cReadSocket
  355.         call cWriteStdout
  356.  
  357.     ; Loop back to the select() system call to check for more data
  358.     check_socket_file_descriptor_done:
  359.     jmp network_read_write_loop
  360.  
  361. network_premature_exit:
  362. network_close_socket:
  363.     ; Syscall close(sockfd);
  364.     mov eax, 6
  365.     mov ebx, [sockfd]
  366.     int 0x80
  367.  
  368.     call cExit
  369.  
  370. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  371. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  372. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  373.  
  374. ;
  375. ; cExit
  376. ;   Exits program with the exit() syscall.
  377. ;       arguments: none
  378. ;       returns: nothing
  379. ;
  380. cExit:
  381.     ; Syscall exit(0);
  382.     mov eax, 1
  383.     mov ebx, 0
  384.     int 0x80
  385.     ret
  386.  
  387. ;
  388. ; cReadStdin
  389. ;   Reads from stdin into readBuffer.
  390. ;   Sets readBuffLen with number of bytes read.
  391. ;       arguments: none
  392. ;       returns: number of bytes read on success, -1 on error, in eax
  393. ;
  394. cReadStdin:
  395.     ; Syscall read(0, readBuffer, readBufferMaxLen);
  396.     mov eax, 3
  397.     mov ebx, 0
  398.     mov ecx, readBuffer
  399.     mov edx, readBufferMaxLen
  400.     int 0x80
  401.  
  402.     mov [readBufferLen], eax
  403.     ret
  404.  
  405. ;
  406. ; cReadSocket
  407. ;   Reads from the socket sockfd into readBuffer.
  408. ;   Sets readBuffLen with number of bytes read.
  409. ;       arguments: none
  410. ;       returns: number of bytes read on success, -1 on error, in eax
  411. ;
  412. cReadSocket:
  413.     ; Syscall read(sockfd, readBuffer, readBufferMaxLen);
  414.     mov eax, 3
  415.     mov ebx, [sockfd]
  416.     mov ecx, readBuffer
  417.     mov edx, readBufferMaxLen
  418.     int 0x80   
  419.  
  420.     mov [readBufferLen], eax
  421.     ret
  422.  
  423. ;
  424. ; cWriteStdout:
  425. ;   Writes readBufferLen bytes of readBuff to stdout.
  426. ;       arguments: none
  427. ;       returns: number of bytes written on success, -1 on error, in eax
  428. ;
  429. cWriteStdout:
  430.     ; Syscall write(1, readBuffer, readBufferLen);
  431.     mov eax, 4
  432.     mov ebx, 1
  433.     mov ecx, readBuffer
  434.     mov edx, [readBufferLen]
  435.     int 0x80
  436.     ret
  437.  
  438. ;
  439. ; cWriteSocket
  440. ;   Writes readBufferLen bytes of readBuff to the socket sockfd.
  441. ;       arguments: none
  442. ;       returns: number of bytes written on success, -1 on error, in eax
  443. ;
  444. cWriteSocket:
  445.     ; Syscall write(sockfd, readBuff, readBuffLen);
  446.     mov eax, 4
  447.     mov ebx, [sockfd]
  448.     mov ecx, readBuffer
  449.     mov edx, [readBufferLen]
  450.     int 0x80
  451.     ret
  452.  
  453. ;
  454. ; cWriteString
  455. ;   Prints message loaded on stack to stdout.
  456. ;       arguments: message to write, message length
  457. ;       returns: nothing
  458. ;
  459. cWriteString:
  460.     push ebp
  461.     mov ebp, esp
  462.  
  463.     ; Syscall write(stdout, message, message length);
  464.     mov eax, 4
  465.     mov ebx, 1
  466.     ; Message poitner
  467.     mov ecx, [ebp+12]
  468.     ; Message length
  469.     mov edx, [ebp+8]
  470.     int 0x80
  471.  
  472.     mov esp, ebp
  473.     pop ebp
  474.     ret
  475.  
  476. ;
  477. ; cStrIP_to_Octets
  478. ;   Parses an ASCII IP address string, e.g. "127.0.0.1", and stores the
  479. ;   numerical representation of the 4 octets in the ipOctets variable.
  480. ;       arguments: pointer to the IP address string
  481. ;       returns: 0 on success, -1 on failure
  482. ;
  483. cStrIP_to_Octets:
  484.     push ebp
  485.     mov ebp, esp
  486.    
  487.     ; Allocate space for a temporary 3 digit substring variable of the IP
  488.     ; address, used to parse the IP address.
  489.     sub esp, 4
  490.    
  491.     ; Point esi to the beginning of the string
  492.     mov esi, [ebp+8]
  493.  
  494.     ; Reset our counter, we'll use this to iterate through the
  495.     ; 3 digits of each octet.
  496.     mov ecx, 0
  497.  
  498.     ; Reset our octet counter, this is to keep track of the 4
  499.     ; octets we need to fill.
  500.     mov edx, 0
  501.  
  502.     ; Point edi to the beginning of the temporary
  503.     ; IP octet substring
  504.     mov edi, ebp
  505.     sub edi, 4
  506.  
  507.     string_ip_parse_loop:
  508.         ; Read the next character from the IP string
  509.         lodsb
  510.         ; Increment our counter
  511.         inc ecx
  512.  
  513.         ; If we encounter a dot, process this octet
  514.         cmp al, '.'
  515.         je octet_complete
  516.         ; If we encounter a null character, process this
  517.         ; octet.
  518.         cmp al, 0
  519.         je null_byte_encountered
  520.         ; If we're already on our third digit,
  521.         ; process this octet.
  522.         cmp ecx, 4
  523.         jge octet_complete
  524.  
  525.         ; Otherwise, copy the character to our
  526.         ; temporary octet string.
  527.         stosb
  528.  
  529.         jmp string_ip_parse_loop
  530.        
  531.     null_byte_encountered:
  532.         ; Check to see if we are on the last octet yet
  533.         ; (current octet would be equal to 3)
  534.         cmp edx, 3
  535.         ; If so, everything is working normally
  536.         je octet_complete
  537.         ; Otherwise, this is a malformed IP address,
  538.         ; and we will return -1 for failure
  539.         mov eax, -1
  540.         jmp malformed_ip_address_exit
  541.    
  542.     octet_complete:
  543.         ; Null terminate our temporary octet variable.
  544.         mov al, 0
  545.         stosb
  546.  
  547.         ; Save our position in the IP address string
  548.         push esi
  549.         ; Save our octet counter
  550.         push edx
  551.  
  552.         ; Send off our temporary octet string to our cStrtoul
  553.         ; function to turn it into a number.
  554.         mov eax, ebp
  555.         sub eax, 4
  556.         push eax
  557.         call cStrtoul
  558.         add esp, 4
  559.  
  560.         ; Check if we had any errors converting the string,
  561.         ; if so, go straight to exit (eax will hold error through)
  562.         cmp eax, 0
  563.         jl malformed_ip_address_exit
  564.  
  565.         ; Restore our octet counter
  566.         pop edx
  567.    
  568.         ; Copy the octet data to the current IP octet
  569.         ; in our IP octet array.   
  570.         mov edi, ipOctets
  571.         add edi, edx
  572.         ; cStrtoul saved the number in eax, so we should
  573.         ; be fine writing al to [edi].
  574.         stosb
  575.  
  576.         ; Increment our octet counter.
  577.         inc edx
  578.        
  579.         ; Restore our position in the IP address string
  580.         pop esi
  581.         ; Reset the position on the temporary octet string
  582.         mov edi, ebp
  583.         sub edi, 4
  584.         ; Continue to processing the next octet
  585.         mov ecx, 0
  586.  
  587.         cmp edx, 4
  588.         jl string_ip_parse_loop
  589.  
  590.     ; Return 0 for success
  591.     mov eax, 0
  592.  
  593.     malformed_ip_address_exit:
  594.     mov esp, ebp
  595.     pop ebp
  596.     ret
  597.  
  598. ;
  599. ; cStrtoul
  600. ;   Converts a number represented in an ASCII string to an unsigned 32-bit
  601. ;   integer.
  602. ;       arguments: pointer to the string
  603. ;       returns: 32-bit integer stored in eax
  604. ;
  605. cStrtoul:
  606.     push ebp
  607.     mov ebp, esp
  608.     ; Allocate space for the multiply operand
  609.     sub esp, 4
  610.  
  611.     ; Point esi to the beginning of the string
  612.     mov esi, [ebp+8]
  613.  
  614.     ; Make a copy of the string address in edi
  615.     mov edi, esi
  616.  
  617.     string_length_loop:
  618.         ; Load the next byte from the string
  619.         lodsb
  620.         ; Compare the byte to the null byte
  621.         cmp al, 0
  622.         ; Continue to loop until the null byte is reached
  623.         jne string_length_loop
  624.  
  625.     ; Copy the address of the null byte + 1 and subtract the
  626.     ; address of the string to have the string length in ebx
  627.     mov ebx, esi
  628.     sub ebx, edi
  629.     ; Decrement by one to account for the null byte
  630.     dec ebx
  631.  
  632.     ; Ensure that the string length > 0
  633.     cmp ebx, 0
  634.     jle premature_exit
  635.  
  636.     ; Use eax to hold the current character
  637.     mov eax, 0
  638.     ; Use ecx to hold the digit position in terms of powers of ten
  639.     mov ecx, 0
  640.     ; Use edx to hold the final result
  641.     mov edx, 0
  642.     ; Set esi back to the beginning of the string so we can traverse it
  643.     mov esi, edi
  644.     digits_count_loop:
  645.         ; Read the next digit into al
  646.         lodsb
  647.         ; Decrement our string length counter
  648.         dec ebx
  649.  
  650.         ; Start out at 10^0 = 1
  651.         mov ecx, 1
  652.         mov edi, 0
  653.         ; Check if we need to multiply by any more powers of 10
  654.         cmp ebx, edi
  655.         ; If not, then ecx = 10^0 = 1, so we can skip the exponent
  656.         ; multiplication loop.
  657.         je exponent_loop_skip
  658.  
  659.         ; Otherwise, multiply ecx by 10 for however many powers
  660.         ; the current digit requires
  661.         exponent_loop:
  662.             imul ecx, 10
  663.             inc edi
  664.             cmp ebx, edi
  665.             jg exponent_loop
  666.        
  667.         exponent_loop_skip:
  668.             ; Check if the character is 0 or greater
  669.             cmp al, 48
  670.             jge lower_bound_met
  671.             ; Otherwise, set the result to 0 and exit
  672.             mov eax, -1
  673.             jmp premature_exit
  674.        
  675.         lower_bound_met:
  676.             ; Check if the character is 9 or less
  677.             cmp al, 57
  678.             jle upper_bound_met
  679.             ; Otherwise, set the result to 0 and exit
  680.             mov eax, -1
  681.             jmp premature_exit
  682.    
  683.         upper_bound_met:   
  684.    
  685.         ; Subtract 48, the ASCII code for '0', from the character,
  686.         ; leaving just the digit in al
  687.         sub al, 48
  688.  
  689.         ; Multiply the powers of ten with the digit
  690.         mov [ebp-4], eax
  691.         imul ecx, [ebp-4]
  692.  
  693.         ; Add this digit value to the final result
  694.         add edx, ecx
  695.  
  696.         ; Continue looping until we have gone through all the digits
  697.         cmp ebx, 0
  698.         jne digits_count_loop  
  699.    
  700.     ; Move the result to eax
  701.     mov eax, edx
  702.  
  703.     premature_exit:
  704.     mov esp, ebp
  705.     pop ebp
  706.     ret
  707.  
  708. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  709. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  710. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Advertisement
Add Comment
Please, Sign In to add comment