Понимание пустого основного () перевод в блок

Вы можете использовать each:

cy.get('p[data-test="ContactID"]').each(($match) => {
  cy.wrap($match).invoke('text').should('not.eq', contactID)
})
  • invoke для вызова функции на объекте, в данном случае .text()
  • в цепочке .should делает утверждение на этом тексте
  • , это будет повторять утверждение до тех пор, пока оно не пройдет или не истечет время ожидания (см. повторная попытка ) из-за cy.wrap

15
задан unwind 7 May 2009 в 09:04
поделиться

5 ответов

Я должен предварять все свои комментарии, говоря, что я все еще учусь правильно.

Я проигнорирую инициализацию раздела. Объяснение инициализации раздела и всего остального, о чем я говорю, можно найти здесь: http://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax

Регистр ebp является базовым указателем кадра стека , отсюда и BP. Он хранит указатель на начало текущего стека.

Регистр esp является указателем стека. Он содержит ячейку памяти вершины стека. Каждый раз, когда мы помещаем что-то в стек, esp обновляется, так что он всегда указывает на адрес, находящийся на вершине стека.

Таким образом, ebp указывает на базу, а esp указывает на вершину. Итак, стек выглядит так:

esp -----> 000a3   fa
           000a4   21
           000a5   66
           000a6   23
esb -----> 000a7   54

Если вы поместите e4 в стек, вот что произойдет:

esp -----> 000a2   e4
           000a3   fa
           000a4   21
           000a5   66
           000a6   23
esb -----> 000a7   54

Обратите внимание, что стек растет в сторону младших адресов, этот факт будет важен ниже.

Первые два шага известны как пролог процедуры или, чаще, пролог функции , они подготавливают стек для использования локальными переменными. pushl% ebp. Поскольку main - это первая вызываемая функция, я не знаю, на что указывает предыдущее значение% ebp.

Шаг 2. Мы вводим новый фрейм стека, потому что мы вводим новую функцию (main). Следовательно, мы должны установить новый указатель базы фрейма стека. Мы используем значение в esp как начало нашего кадра стека.

Шаг 3. Выделяет 8 байтов пространства в стеке. Как мы упоминали выше, стек увеличивается в сторону младших адресов, поэтому при вычитании на 8 верх стека перемещается на 8 байт.

Шаг 4; Выравнивает стек, я нашел разные мнения по этому поводу. Я не совсем уверен, что именно это было сделано. Я подозреваю, что это сделано для того, чтобы разрешить размещение больших инструкций (SIMD) в стеке,

http://gcc.gnu.org/ml/gcc/2008-01/msg00282.html

Этот код "и "s ESP с 0xFFFF0000, выравнивание стека со следующим нижняя 16-байтовая граница. изучение исходного кода Mingw показывает, что это может быть для SIMD инструкции в "_main" процедуры, которые работают только на согласованных адреса. Поскольку наша рутина не содержат инструкции SIMD, эта строка

http://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax

Шаги с 5 по 11 кажутся мне бесполезными. Я не мог найти объяснения в Google. Может ли кто-нибудь, кто действительно разбирается в этом, глубже понять. До меня доходили слухи, что этот материал используется для обработки исключений C.

Шаг 5 сохраняет возвращаемое значение основного 0 в eax.

На шагах 6 и 7 мы добавляем 15 в шестнадцатеричном формате к eax по неизвестной причине. eax = 01111 + 01111 = 11110

На шаге 8 мы сдвигаем биты eax на 4 бита вправо. eax = 00001, потому что последние биты сдвинуты с конца 00001 | 111.

На шаге 9 мы сдвигаем биты eax на 4 бита влево, eax = 10000.

На шагах 10 и 11 значение в первых 4 выделенных байтах в стеке перемещается в eax, а затем перемещается из eax обратно.

Шаги 12 и 13 устанавливают библиотеку c.

Мы достигли эпилога функции . То есть часть функции, которая возвращает указатели стека, esp и ebp, в состояние, в котором они находились до вызова этой функции.

Шаг 14, leave устанавливает esp на значение ebp, перемещая верх стека в адрес, который был до вызова main. Затем он устанавливает ebp таким образом, чтобы он указывал на адрес, который мы сохранили в верхней части стека на шаге 1.

Leave можно просто заменить следующими инструкциями:

mov  %ebp, %esp
pop  %ebp

Шаг 15, возврат и выход из функции.

1.    pushl       %ebp
2.    movl        %esp, %ebp
3.    subl        $8, %esp
4.    andl        $-16, %esp
5.    movl        $0, %eax
6.    addl        $15, %eax
7.    addl        $15, %eax
8.    shrl        $4, %eax
9.    sall        $4, %eax
10.   movl        %eax, -4(%ebp)
11.   movl        -4(%ebp), %eax
12.   call        __alloca
13.   call        ___main
14.   leave
15.   ret

Процедура Пролог:

Первое, что должна сделать функция перемещение вершины стека по адресу, который был до вызова main. Затем он устанавливает ebp таким образом, чтобы он указывал на адрес, который мы сохранили в верхней части стека на шаге 1.

Leave можно просто заменить следующими инструкциями:

mov  %ebp, %esp
pop  %ebp

Шаг 15, возврат и выход из функции.

1.    pushl       %ebp
2.    movl        %esp, %ebp
3.    subl        $8, %esp
4.    andl        $-16, %esp
5.    movl        $0, %eax
6.    addl        $15, %eax
7.    addl        $15, %eax
8.    shrl        $4, %eax
9.    sall        $4, %eax
10.   movl        %eax, -4(%ebp)
11.   movl        -4(%ebp), %eax
12.   call        __alloca
13.   call        ___main
14.   leave
15.   ret

Процедура Пролог:

Первое, что должна сделать функция перемещение вершины стека по адресу, который был до вызова main. Затем он устанавливает ebp таким образом, чтобы он указывал на адрес, который мы сохранили в верхней части стека на шаге 1.

Leave можно просто заменить следующими инструкциями:

mov  %ebp, %esp
pop  %ebp

Шаг 15, возврат и выход из функции.

1.    pushl       %ebp
2.    movl        %esp, %ebp
3.    subl        $8, %esp
4.    andl        $-16, %esp
5.    movl        $0, %eax
6.    addl        $15, %eax
7.    addl        $15, %eax
8.    shrl        $4, %eax
9.    sall        $4, %eax
10.   movl        %eax, -4(%ebp)
11.   movl        -4(%ebp), %eax
12.   call        __alloca
13.   call        ___main
14.   leave
15.   ret

Процедура Пролог:

Первое, что должна сделать функция называется прологом процедуры. Это сначала сохраняет текущий базовый указатель (ebp) с инструкцией pushl% ebp (помните, что ebp - это регистр, используемый для доступ к параметрам функции и локальные переменные). Теперь он копирует указатель стека (esp) на базу указатель (ebp) с инструкцией movl% esp,% ebp. Это позволяет вам доступ к параметрам функции как индексы из базового указателя. Местный переменные всегда являются вычитанием от ebp, например -4 (% ebp) или (% ebp) -4 для первой локальной переменной, возвращаемое значение всегда равно 4 (% ebp) или (% ebp) +4, каждый параметр или аргумент равен N * 4 + 4 (% ebp), например 8 (% ebp) для первого аргумента, а старый ebp находится в (% ebp).

http://www.milw0rm.com/papers/52

Существует действительно отличный поток переполнения стека, который отвечает на большую часть этого вопроса. Почему в моем выводе gcc есть лишние инструкции?

Хороший справочник по инструкциям машинного кода x86 можно найти здесь: http://programminggroundup.blogspot.com/2007/01/appendix-b-common-x86-instructions.html

Это лекция, которая содержит некоторые из идей, используемых ниже: http://csc.colstate.edu/bosworth/cpsc5155/Y2006_TheFall/MySlides/CPSC5155_L23.htm

Вот еще один вариант ответа на ваш вопрос: http://www.phiral.net/linuxasmone.htm

Ни один из этих источников не объясняет всего.

14
ответ дан 1 December 2019 в 01:53
поделиться

Как ни странно, эти шаблоны, похоже, вообще не настраиваются.

Возможно, вы захотите посмотреть этот вопрос . Также этот блог . Google, вероятно, даст вам гораздо больше.

или, возможно, функция ядра, которая вызвала вашу программу)
9
ответ дан 1 December 2019 в 01:53
поделиться

Ну, я не очень разбираюсь в GAS, и я немного заржавел на сборке Intel, но похоже, что он инициализирует основной стек стека.

Если вы посмотрите, __main какой-то макрос должен выполнять инициализации. Затем, поскольку тело main пусто, оно вызывает инструкцию ухода, чтобы вернуться к функции, которая вызвала main.

Из http://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax#.22hello.s. 22_line-by-line :

В этой строке объявляется метка «_main», обозначающая место, которое вызывается из кода запуска.

    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp

Эти строки сохраняют значение EBP в стеке, а затем перемещают значение ESP в EBP, затем вычтите 8 из ESP. «L» в конце каждого кода операции указывает, что мы хотим использовать версию кода операции, которая работает с «длинными» (32-разрядными) операндами;

    andl    $-16, %esp

Этот код »и« ESP с 0xFFFF0000, выравнивая стек со следующей нижней 16-байтовой границей. (необходимо при использовании инструкций simd, здесь не полезно)

    movl    $0, %eax
    movl    %eax, -4(%ebp)
    movl    -4(%ebp), %eax

Этот код перемещает ноль в EAX, затем перемещает EAX в ячейку памяти EBP-4, который находится во временном пространстве, которое мы зарезервировали в стеке в начале процедуры. Затем он перемещает ячейку памяти EBP-4 обратно в EAX; очевидно, это не оптимизированный код.

    call    __alloca
    call    ___main

Эти функции являются частью настройки библиотеки C. Поскольку мы вызываем функции в библиотеке C, они, вероятно, нам нужны. Точные операции, которые они выполняют, различаются в зависимости от платформы и версии установленных инструментов GNU.

Вот полезная ссылка.

http://unixwiz.net/techtips/win32-callconv-asm.html

4
ответ дан 1 December 2019 в 01:53
поделиться

Похоже, что GCC действует так, как будто можно отредактировать main () , чтобы включить код инициализации CRT. Я только что подтвердил, что я получаю точно такой же лист сборки из MinGW GCC 3.4.5 здесь, с вашим исходным текстом.

Командная строка, которую я использовал:

gcc -S emptymain.c

Интересно, если я изменю имя функции на qqq () вместо main () , я получаю следующую сборку:

        .file   "emptymain.c"
        .text
.globl _qqq
        .def    _qqq;      .scl    2;      .type   32;     .endef
_qqq:
        pushl   %ebp
        movl    %esp, %ebp
        popl    %ebp
        ret

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

1
ответ дан 1 December 2019 в 01:53
поделиться

It would really help to know what gcc version you are using and what libc. It looks like you have a very old gcc version or a strange platform or both. What's going on is some strangeness with calling conventions. I can tell you a few things:

Save the frame pointer on the stack according to convention:

pushl       %ebp
movl        %esp, %ebp

Make room for stuff at the old end of the frame, and round the stack pointer down to a multiple of 4 (why this is needed I don't know):

subl        $8, %esp
andl        $-16, %esp

Through an insane song and dance, get ready to return 1 from main:

movl        $0, %eax
addl        $15, %eax
addl        $15, %eax
shrl        $4, %eax
sall        $4, %eax
movl        %eax, -4(%ebp)
movl        -4(%ebp), %eax

Recover any memory allocated with alloca (GNU-ism):

call        __alloca

Announce to libc that main is exiting (more GNU-ism):

call        ___main

Restore the frame and stack pointers:

leave

Return:

ret

Here's what happens when I compile the very same source code with gcc 4.3 on Debian Linux:

        .file   "main.c"
        .text
        .p2align 4,,15
.globl main
        .type   main, @function
main:
        leal    4(%esp), %ecx
        andl    $-16, %esp
        pushl   -4(%ecx)
        pushl   %ebp
        movl    %esp, %ebp
        pushl   %ecx
        popl    %ecx
        popl    %ebp
        leal    -4(%ecx), %esp
        ret
        .size   main, .-main
        .ident  "GCC: (Debian 4.3.2-1.1) 4.3.2"
        .section        .note.GNU-stack,"",@progbits

And I break it down this way:

Tell the debugger and other tools the source file:

        .file   "main.c"

Code goes in the text section:

        .text

Beats me:

        .p2align 4,,15

main is an exported function:

.globl main
        .type   main, @function

main's entry point:

main:

Grab the return address, align the stack on a 4-byte address, and save the return address again (why I can't say):

        leal    4(%esp), %ecx
        andl    $-16, %esp
        pushl   -4(%ecx)

Save frame pointer using standard convention:

        pushl   %ebp
        movl    %esp, %ebp

Inscrutable madness:

        pushl   %ecx
        popl    %ecx

Restore the frame pointer and the stack pointer:

        popl    %ebp
        leal    -4(%ecx), %esp

Return:

        ret

More info for the debugger?:

        .size   main, .-main
        .ident  "GCC: (Debian 4.3.2-1.1) 4.3.2"
        .section        .note.GNU-stack,"",@progbits

By the way, main is special and magical; when I compile

int f(void) {
  return 17;
}

I get something slightly more sane:

        .file   "f.c"
        .text
        .p2align 4,,15
.globl f
        .type   f, @function
f:
        pushl   %ebp
        movl    $17, %eax
        movl    %esp, %ebp
        popl    %ebp
        ret
        .size   f, .-f
        .ident  "GCC: (Debian 4.3.2-1.1) 4.3.2"
        .section        .note.GNU-stack,"",@progbits

There's still a ton of decoration, and we're still saving the frame pointer, moving it, and restoring it, which is utterly pointless, but the rest of the code make sense.

4
ответ дан 1 December 2019 в 01:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: