Как написать свою собственную функцию Atoi в сборке x86 - PullRequest
2 голосов
/ 08 апреля 2019

У меня возникли проблемы с написанием моей собственной функции Atoi в сборке.Инструкции:

"Измените функцию таким образом, чтобы она возвращала целочисленный эквивалент C-строки (указатель), который передается в функцию. Вы можете предположить, что первый символ находится в диапазоне от '0' до '9', включительно. atoish должен учитывать все символы от первого до первого символа, который не является десятичной цифрой. Как вы можете видеть, mainusus возвращает значение, возвращаемое atoias кодом выхода (это просто дешевый способ доступа к выводу изatoi, без записи itoafunction.) Как дано вам, atoireturns 1234. Возвращаемое значение равно ANDedwith 0xFF, чтобы уменьшить его до байта. Таким образом, 1234 & 255 становится 210. "

    # Useful constants 
    .equ    STDIN,0 
    .equ    STDOUT,1 
    .equ    READ,0 
    .equ    WRITE,1 
    .equ    EXIT,60 
# Stack frame 
    .equ    bufferSize, 32
    .equ    buffer,-bufferSize
    .equ    localSize,16 
    .equ    frameSize, bufferSize + localSize
# Read only data 
    .section    .rodata # the read-only data section 
prompt: 
    .string     "Enter an integer: " 
    .equ    promptSz,.-prompt-1 
msg: 
    .string     "You entered: " 
    .equ    msgSz,.-msg-1 

Code

    .text   # switch to text section 


    .globl  __start 
 __start: 
    pushq   %rbp    # save caller’s frame pointer 
    movq    %rsp, %rbp  # establish our frame pointer 
    subq    $frameSize, %rsp    # for local variables 

    movl    $promptSz, %edx # prompt size 
    movl    $prompt, %esi   # address of prompt text string 
    movl    $STDOUT, %edi   # standard out 
    movl    $WRITE, %eax 
    syscall     # request kernel service 

    movl    $bufferSize,%edx
    leaq    buffer(%rbp), %rsi  # load buffer address
    movl    $STDIN, %edi    # standard in 
    movl    $READ, %eax 
    syscall     # request kernel service 
    movl    %eax, (%rsp)    # store num chars read

    leaq    buffer(%rbp), %rsi  # load buffer address
    call    atoi    # our exit code will be the return from atoi

    movq    %rbp, %rsp  # delete local variables 
    popq    %rbp    # restore caller’s frame pointer 
    movl    %eax, %edi  # put exit status in %edi (will be ANDed with FF)
    movl    $EXIT, %eax # exit from this process 

    syscall

базовый код выглядит так, где мне просто нужно реализовать свой собственный atoi.пока что у меня есть функция atoi:

atoi:
    pushq   %rbp    # save caller’s frame pointer 
    movq    %rsp, %rbp  # establish our frame pointer 
    subq    $16, %rsp   # for local variables

    movq    %rdi, -16(%rbp) #moving first argument to local variable
    movl    $0, -4(%rbp) #moving 0 to local variable
    movl    $10, -12(%rbp) #moving 10 to local variable

    movl    -16(%rbp), %rax
    movzbl  (%rax), %eax #getting value of rax
    movl    -4(%rbp), %eax

    imull   -12(%rbp), %eax
    movl    %eax,   -4(%rbp)

    movq    %rbp, %rsp  # delete local variables 
    popq    %rbp    # restore caller’s frame pointer 
    ret

я в растерянности, чтобы узнать, куда идти дальше.кажется, все, что я делаю, только дает мне ошибки сегментации

1 Ответ

0 голосов
/ 08 апреля 2019

Вы чрезмерно используете локальные переменные (и недостаточно используете регистры); понадобится цикл, который останавливается, когда он находит недопустимый символ; и, возможно, использование неправильных соглашений о вызовах (системные вызовы похожи на Linux, что подразумевает ABI-интерфейс System V AMD64, что означает, что параметры передаются в регистрах, а не в стеке).

Обратите внимание, что все это можно сделать без каких-либо локальных переменных. Например (синтаксис NASM, потому что я не делаю AT & T, не проверено):

;Convert string to integer
;
;Input
; rdi = first parameter (address of string)
;
;Output
; rax = result

atoi:
    xor rax,rax               ;rax = 0 (this will become the returned result)
.nextChar:
    movzx rcx,byte [rdi]      ;rcx = next character
    sub rcx,'0'               ;rcx = value of next digit
    jb .done                  ;Invalid character (too low to be a decimal digit)
    cmp rcx,9                 ;Was it too high to be a decimal digit?
    ja .done                  ; yes, invalid

    lea rax,[rax*4+rax]       ;rax = result*5
    lea rax,[rax*2+rcx]       ;rax = result*5*2 + digit = result*10 + digit
    inc rdi                   ;rdi = address of next character
    jmp .nextChar
.done:
     ret

Примечание. Этот код не будет работать для отрицательных значений (например, строк, начинающихся с '-') и не будет возвращать состояние ошибки, если / когда результат переполнен. Результат также будет 64-битным (в то время как int, вероятно, должен быть 32-битным). В основном это «конвертировать в unsigned long long» (с обработкой ошибок, которая так же плоха, как atoi()).

...