Ошибка сегментации при выполнении программы, скомпилированной из сборки x86? - PullRequest
0 голосов
/ 22 декабря 2009

Я новичок в ассемблере, и мне нужно реализовать функцию, в моем случае sin (x), которая может вызываться из исходного файла C. Я должен сделать 2 отдельных файла: * .c и * .s При компиляции через gcc на ubuntu все хорошо, но при запуске программы выдает ошибку "Ошибка сегментации" ...

Для компиляции набираю:

gcc -c -o sinc.o sinx.c -g3
gcc -c -o sins.o sinx.s -g3
gcc -o sinx sinc.o sins.o -g3

Когда я запускаю программу:

./sinx

Он печатает:

.......insert x:

Я положил x, а затем:

segmentation fault

и это останавливается. Вот два файла:

/*-----------------------------------Sin[x]----------------------------------------*/

extern float Sin(float x);                                //extern assembly function

#include <stdio.h>                                             //necessary libraries

int main()                                                          // main function
{
    float x;                                      //allocate variable 'x' as a float
    float sine;                                //allocate variable 'sine' as a float

    printf("Calculate Sin[x], with 'x' in radians\n");      //purpose of the program

    printf("Insert 'x': ");                                            //user prompt
    scanf("%f",&x);                                                //get input value

    sine=Sin(x);                                                   //calculate sin(x)

    printf("Sin[%f]=%f\n",x,sine);                                     //print sin(x)

    return 0;                                                       //successful exit
}
/*----------------------------------------------------------------------------------*/

и

#---------------------------Sin[x]-----------------------------#
.data
.text
.globl Sin             #global function visible by main function

#function sumplus
sumplus:
   pushl  %ebp
   movl   %esp,%ebp
   fld1                                             #load 1 in ST(0)
   movl   12(%ebp),%ecx                                       #ecx=i
power:
   fmul   %st(0),%st(1)                   #ST(0)=ST(0)*ST(1),ST(1)=x
   loop   power                                #at the end ST(0)=x^i
   movl   12(%ebp),%ecx                                       #ecx=i
   xorl   %edx,%edx                           #reset edx used in mul
   movl   $1,%eax                                   #set accumulator
factorial:
   mul    %ecx                                          #eax=eax*ecx
   loop   factorial                               #at the end eax=i!
   pushl  %eax
   fild   -4(%ebp)                       #ST(0)=i!,ST(1)=x^i,ST(2)=x
   popl   %eax
   fdiv   %st(1),%st(0)                  #ST(1)=ST(1)/ST(0)=(x^i)/i!
   fld    8(%ebp)                      #load partial result in ST(0)
   fadd   %st(0),%st(2)                #ST(0)=updated partial result
   fstp   8(%ebp)               #store partial result into the stack
   fcomip %st(0),%st(0)                                      #pop i!
   fcomip %st(0),%st(0)                          #pop x^i/i!,ST(0)=x
   leave
   ret

#function summinus
summinus:
   pushl  %ebp
   movl   %esp,%ebp
   fld1                                             #load 1 in ST(0)
   movl   12(%ebp),%ecx                                       #ecx=i
power2:
   fmul   %st(0),%st(1)                   #ST(0)=ST(0)*ST(1),ST(1)=x
   loop   power2                               #at the end ST(0)=x^i
   movl   12(%ebp),%ecx                                       #ecx=i
   xorl   %edx,%edx                           #reset edx used in mul
   movl   $1,%eax                                   #set accumulator
factorial2:
   mul    %ecx                                          #eax=eax*ecx
   loop   factorial2                              #at the end eax=i!
   pushl  %eax
   fild   -4(%ebp)                       #ST(0)=i!,ST(1)=x^i,ST(2)=x
   popl   %eax
   fdiv   %st(1),%st(0)                  #ST(1)=ST(1)/ST(0)=(x^i)/i!
   fld    8(%ebp)                      #load partial result in ST(0)
   fsub   %st(0),%st(2)                #ST(0)=updated partial result
   fstp   8(%ebp)               #store partial result into the stack
   fcomip %st(0),%st(0)                                      #pop i!
   fcomip %st(0),%st(0)                          #pop x^i/i!,ST(0)=x
   leave
   ret

#function develop
develop:
   pushl %ebp
   movl  %esp,%ebp
   sub   $8,%esp                #allocate room for local variables
   movl  $9,-4(%ebp)       #store development-order,only odd values
   fldz                                          #load 0.0 in ST(0)
   fstp  -8(%ebp)           #store ST(0) and pop to collect results
Cycle:
   movl   -4(%ebp),%eax                    #eax=i,development-order
   xorl   %edx,%edx                       #reset edx because of div
   sub    $1,%eax                                              #i-1
   movl   $2,%ecx                                          #divisor
   div    %ecx                                   #eax=(i-1)/2,edx=0
   div    %ecx           #eax=((i-1)/2)/2,remainder edx=0 or edx!=0
   movl   %edx,%ecx                                  #ecx=remainder
   jecxz  Sumplus                                 #n even,(-1)^n=+1
Summinus:
   call   summinus                                 #n odd,(-1)^n=-1
   jmp    Restore                        #if sum- occured skip sum+
Sumplus:
   call   sumplus
Restore:
   movl   -4(%ebp),%ecx                            #restore counter
   sub    $2,-4(%ebp)                                 #update order
   loop   Cycle                                      #decrement ecx
   fcomip %st(0),%st(0)                                      #pop x
   fld    -8(%ebp)                       #load final result in ST(0)
   leave
   ret

#function sin
Sin:
   pushl %ebp
   movl  %esp,%ebp
   fld   8(%ebp)                   #push onto the stack 'x' value
   fldpi                           #load pi into ST(0),x in ST(1)
ControlPi:
   fcomi  %st(1)                                #compare pi and x
   jae    LoadNPi              #stop ControlPi, x is less than pi 
   fsub   %st(1),%st(0)                     #store (x-pi) in ST(1)
   jmp    ControlPi                            #return to control 
LoadNPi:            
   fimul   -1                           #(-pi) in ST(0),x in ST(1)                   
ControlPi2:
   fcomi  %st(1)                               #compare -pi and x
   jbe    PopStack        #stop ControlPi2, x is greater than -pi
   fadd   %st(1),%st(0)                     #store (x+pi) in ST(1)
   jmp    ControlPi2                           #return to control
PopStack:
   fcomip %st,%st(0)   #compare -pi to -pi then pop register stack
   call  develop                            #call develop function
   leave                                              #restore ebp
   ret                                                     #return

Итак, где ошибки? Как я могу решить эту проблему? Спасибо.

Ответы [ 4 ]

4 голосов
/ 22 декабря 2009

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

float identity(float x) {
    return x;
}

Выполнение этой работы обеспечит правильную настройку всех компиляций, сборок, компоновки, соглашений о вызовах и т. Д., Прежде чем вы начнете писать код. Как только это сработает, напишите функцию, чтобы добавить 1 к аргументу и вернуть его. Затем начните реализовывать вашу Sin() функцию после того, как вы немного потренировались. То, что у вас есть, - это чертовски много кода для кого-то нового в ассемблере.

2 голосов
/ 22 декабря 2009

Вы действительно ожидаете, что кто-то отладит это для вас как есть?

Пройдите инструкцию по сборке в отладчике, а затем задайте вопрос. «Мои регистры имеют значения a, b, c ..., и я выполнил инструкцию, бла». Почему эта ловушка? Для подготовки вы должны были как минимум прочитать текст инструкции по отлову в справочнике по набору инструкций Intel, доступном здесь:

http://www.intel.com/products/processor/manuals/

1 голос
/ 07 марта 2010

В этой ассемблерной функции более одной ошибки:)

  1. Использование gdb показывает, что произошла ошибка по команде fimul.
  2. Вы не можете использовать fimul с таким литеральным операндом; операндом должен быть адрес 32-битного значения, на которое вы хотите умножить, а не само буквальное значение.
  3. Чтобы изменить знак st0, определенно проще использовать fchs.
  4. Даже с этими изменениями ваша ассемблерная функция не работает (но, по крайней мере, она не выполняет segfault и возвращает правильное значение в случае, когда аргумент равен нулю!)
1 голос
/ 22 декабря 2009

Как правило, семейство регистров топоров (включая eax) должно содержать возвращаемое значение в сборке. Вы проверили и подтвердили, что значение действительно хранится там. Возможно, вы захотите использовать обработчик сигнала и перехватить SIGSEGV и выполнить system(...) обстрел GDB, используя getpid(), подключиться к процессу и выполнить трассировку стека.

В качестве примера функции, используемой в обработчике сигнала при захвате SIGSEGV:

char buf[150];
sprintf(buf, "echo where | gdb -a %d > mydump.data", getpid());
system(buf);

Затем вы можете проверить файл mydump.data и проверить, где именно он является ошибкой сегмента.

Сегфоулты являются результатом разыменования неинициализированного указателя или неправильного указания.

Надеюсь, это поможет, С наилучшими пожеланиями, Том.

...