Почему я получаю другой результат при трассировке в write (), чем другие люди? - PullRequest
0 голосов
/ 16 октября 2011

Я делаю некоторые упражнения x86;мое назначение заставляет меня пошагово проходить через код ассемблера для вызова библиотеки write() в отладчике, пока мы не достигнем инструкции SYSENTER, но я получаю результаты, отличные от результатов некоторых моих одноклассников.То, что я увидел до SYSENTER, было:

   │0xf7fdf421 <__kernel_vsyscall+1>        push   %edx                                                                                            
   │0xf7fdf422 <__kernel_vsyscall+2>        push   %ebp                                                                                            
   │0xf7fdf423 <__kernel_vsyscall+3>        mov    %esp,%ebp                                                                                       
   │0xf7fdf425 <__kernel_vsyscall+5>        sysenter    

Это то, что я должен увидеть?Если так, почему это отличается от того, что видели некоторые из моих одноклассников?Также регистры% edx и% ebp сохраняются в стеке перед выполнением инструкции sysenter?(Разве это не будет выглядеть согласно полученному ответу или я ошибаюсь?)

Вот мои оригинальные инструкции из моего задания:

Код сборки:

.file    "A3Program2.c"
    .section    .rodata
.LC0:
    .string    "hello\n"
.LC1:
    .string    "xxxx\n"
    .text
.globl secondCall
    .type    secondCall, @function
secondCall:
    pushl    %ebp
    movl    %esp, %ebp
    subl    $40, %esp
    movl    $6, 8(%esp)
    movl    $.LC0, 4(%esp)
    movl    $1, (%esp)
    call    write
    movl    %eax, -12(%ebp)
    movl    $8, 8(%esp)
    movl    $.LC1, 4(%esp)
    movl    $1, (%esp)
    call    write
    addl    %eax, -12(%ebp)
    movl    12(%ebp), %eax
    movl    8(%ebp), %edx
    leal    (%edx,%eax), %eax
    addl    %eax, -12(%ebp)
    movl    -12(%ebp), %eax
    leave
    ret
    .size    secondCall, .-secondCall
.globl firstCall
    .type    firstCall, @function
firstCall:
    pushl    %ebp
    movl    %esp, %ebp
    subl    $40, %esp
    movl    $2, 4(%esp)
    movl    $4, (%esp)
    call    secondCall
    movl    %eax, -12(%ebp)
    movl    -12(%ebp), %eax
    leave
    ret
    .size    firstCall, .-firstCall
.globl main
    .type    main, @function
main:
    pushl    %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $16, %esp
    call    firstCall
    movl    %eax, 12(%esp)
    movl    $0, %eax
    leave
    ret
    .size    main, .-main
    .ident    "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
    .section    .note.GNU-stack,"",@progbits

Следующие инструкции предназначены для Linux:

Найдите номер строки второго вызова для записи «call write» в функции secondCall.Установите точку останова на этой линии.Который 22 по мне.

Установите точку останова в этой строке.

 break 22

Запустите программу внутри отладчика.

 run

Программа остановится на заданной вами точке останова.Войдите в код, который не имеет отладочной информации.

  si 

Вы увидите «[Источник недоступен]» в макете исходного кода.Поэтому вам нужно просмотреть разобранные инструкции.

 layout asm

Повторно переходите к (si, а затем return / enter будет выполнять команду si несколько раз), пока вы не увидите «sysenter» в разделе asm-макета экрана.,Я пытаюсь скопировать инструкции (включая их адреса) из верхней части раздела разметки asm, вплоть до инструкции sysenter, включая ее.

Подсказка: вы можете изменить фокус клавиатуры на область команд, выполнивнабрав Ctrl-x o.Таким образом, клавиши со стрелками могут использоваться для возврата более ранних команд (это просто экономит время при наборе текста).

1 Ответ

10 голосов
/ 16 октября 2011

Вы прослеживаете то, что называется 'виртуальный динамический общий объект' (VDSO) - содержимое которого является подробностью реализации ядра linux. Существует ряд условий, которые могут привести к изменению содержимого VDSO; как таковой здесь нет единственно правильного ответа .

В частности, в 32-битных системах x86 существует как минимум три различных механизма, которые можно использовать для системного вызова:

  • INT $0x80
  • SYSCALL (последние процессоры AMD)
  • SYSENTER (последние процессоры Intel)

Вы заметите, что только INT $0x80 работает на всех процессорах (действительно, ядро ​​делает его доступным для устаревших приложений, даже когда доступны и более современные альтернативы); однако, это также медленно. Ядро проверит, какие из них поддерживаются во время загрузки, и выберет версию VDSO, в которой используется наиболее эффективный из доступных механизмов.

Таким образом, в зависимости от модели вашего процессора, вы можете увидеть другой код в VDSO - в частности, если у вас процессор AMD, вы, вероятно, увидите путь SYSCALL, и если у вас действительно старый CPU вы можете даже увидеть путь INT $0x80. Если вас интересуют другие, вот исходный код:

Скорее всего, другие люди в вашей лаборатории, которые получили другой результат, имели процессор AMD и смотрели на путь SYSCALL (или у них был старинный ПК, и они смотрели на путь INT $0x80).

Обратите внимание, что в 64-битном процессе SYSCALL будет использоваться напрямую, без прохождения VDSO вообще.

...