Получение segfault с вызовом atoi

Мне нужно работать с x86 для домашнего задания. Я продолжаю получать этот segfault для вызова atoi, но я не уверен, почему это происходит. Это код:

    addl    $4, %eax
    movl    (%eax), %eax
    movl    %eax, (%esp)
    call    atoi

Где $eax прямо перед "call atoi" равно "11". Чтобы доказать это, это то, что я получаю в gdb прямо перед вызовом.

  x/s $eax
  0xffffd658:    "11"

Я предполагаю, что мой большой вопрос заключается в том, что должно храниться в регистре $eax перед «вызовом atoi» и что должно храниться в $eax для программы, чтобы затем выполнить segfault в «вызове atoi»?

РЕДАКТИРОВАТЬ: Кто-то попросил регистры.

  (gdb) x/s $eax
  0xffffd658:    "11"
    (gdb) n

Program received signal SIGSEGV, Segmentation fault.
0x2aaaaaa3 in ?? ()
(gdb) inf r
eax            0x0  0
ecx            0x2aaaaaab   715827883
edx            0x0  0
ebx            0x2c3ff4 2899956
esp            0xffffd458   0xffffd458
ebp            0x80484ef    0x80484ef
esi            0x0  0
edi            0x0  0
eip            0x2aaaaaa3   0x2aaaaaa3
eflags         0x10287  [ CF PF SF IF RF ]
cs             0x23 35
ss             0x2b 43
ds             0x2b 43
es             0x2b 43
fs             0x0  0
gs             0x63 99
(gdb) 

person AbhishekSaha    schedule 20.03.2014    source источник
comment
Можете ли вы сбросить информацию обо всех регистрах во время segfault, используя команду gdb inf r.   -  person Mantosh Kumar    schedule 20.03.2014


Ответы (1)


Это зависит от того, ожидает ли ваша функция atoi указатель в %eax или в стеке. Вы, кажется, не определились с этим, учитывая сегмент кода:

movl    %eax, (%esp)
call    atoi

Если это должно помещать адрес в стек, вам нужно либо на самом деле push его (что корректно изменяет указатель стека), либо изменить указатель стека самостоятельно (например, с помощью sub %esp, 4 или чего-то подобного).

Указатель стека x86 указывает на последнюю добавленную запись, поэтому push сначала уменьшает указатель стека, а затем сохраняет значение в новом указателе. Это означает, что movl %eax (%esp) собирается испортить последнюю помещенную в стек запись, а не поместить в стек новое значение.

Большинство людей позволяют ЦП обрабатывать стек данных, а не пытаться сделать это вручную, поэтому вы, вероятно, ищете:

push %eax

Однако, если вместо этого atoi ожидает свой аргумент в %eax, а не в стеке, зачем записывать его в стек? Это все равно испортит все, что там было.

Итак, первое, что я бы сделал, это выбрать (для выдвинутого значения):

addl    $4, %eax
movl    (%eax), %eax
push    %eax
call    atoi

или (для использования %eax), просто:

addl    $4, %eax
movl    (%eax), %eax
call    atoi
person paxdiablo    schedule 20.03.2014
comment
Это всего лишь подмножество моего кода, я могу опубликовать его целиком, если это будет более полезно. - person AbhishekSaha; 20.03.2014
comment
@Abhishek, я сомневаюсь, что дополнительный код поможет. Вероятно, вы неправильно вводите значение адреса. Вам нужно push значение, чтобы esp изменилось, а не просто записать его в текущее esp, оставив esp без изменений. - person paxdiablo; 20.03.2014
comment
Я дам вам чек, потому что вы привели меня к правильному ответу; моя ошибка заключалась в том, что я забыл, что порядок инициализации оператора был movl %esp, %ebp вместо того, что у меня есть там - person AbhishekSaha; 20.03.2014