201036: push %rbp
201037: push %rbx
201038: sub $0x28,%rsp
20103c: mov %rsp,%rsi
20103f: callq 2014a5 <read_input>
201044: cmpl $0x0,(%rsp)
201048: jne 201051 <func_2+0x1b>
20104a: cmpl $0x1,0x4(%rsp)
20104f: je 201056 <func_2+0x20>
201051: callq 20146f <wrong_input>
201056: mov %rsp,%rbp
201059: lea 0x4(%rsp),%rbx
20105e: add $0x18,%rbp
201062: mov -0x2(%rbx),%eax
201065: add -0x4(%rbx),%eax
201068: cmp %eax,(%rbx)
20106a: je 201071 <func_2+0x3b>
20106c: callq 20146f <wrong_input>
201071: add $0x2,%rbx
201075: cmp %rbp,%rbx
201078: jne 201062 <func_2+0x2c>
20107a: add $0x28,%rsp
20107e: pop %rbx
20107f: pop %rbp
201080: retq
Ну, если я разобью его на строки:
mov %rsp,%rbp : puts value of rsp into rbp
lea 0x4(%rsp),%rbx : put "0x4*rsp" into rbx. (*rsp = address of or rsp)
add $0x15,%rbp : adds the integer that at "0x15" to rbp and saves the sum in
rbp.
mov -0x2(%rbx),%eax : moves the value that inside of ??? to eax
add -0x4(%rbx),%eax : adds the value that inside of ??? to eax as saves the sum
in eax.
cmp %eax,(%rbx): compares eax with rbx.
ну, я не очень понимаю, что означает "0x4(%rsp)", что означает минус в "-0x2(%rbx)" и "-0x4(%rbx)"..
Я пытаюсь соединить точки здесь. Это похоже на цикл, который увеличивает rbx или eax, а затем сравнивает их.. Хотя я действительно этого не понимаю.
... Я не очень понимаю, что означает "0x4(%rsp)", что означает минус в "-0x2(%rbx)" и "-0x4(%rbx)"..
Эти числа должны быть добавлены к значению в скобках, число является компонентом смещения.
В 0x4(%rsp)
истинным адресом становится значение в регистре %RSP
плюс 4.
В -0x2(%rbx)
истинным адресом становится значение в регистре %RBX
минус 2.
например Если в mov -0x2(%rbx),%eax
регистр %RBX
содержит 100002, то регистр %EAX
получает двойное слово, хранящееся по адресу памяти 100000.
например Если в lea 0x4(%rsp),%ebx
регистр %RSP
содержит 100000, то регистр %EBX
получает значение 100004.
[код был добавлен]
Теперь, когда вы добавили больше кода, мы можем попытаться выяснить, как может работать цикл.
mov %rsp,%rsi
callq 2014a5 <read_input>
cmpl $0x0,(%rsp)
jne 201051 <func_2+0x1b>
cmpl $0x1,0x4(%rsp)
je 201056 <func_2+0x20>
201051: callq 20146f <wrong_input>
201056: mov %rsp,%rbp
lea 0x4(%rsp),%rbx
add $0x18,%rbp
201062: mov -0x2(%rbx),%eax
add -0x4(%rbx),%eax
cmp %eax,(%rbx)
je 201071 <func_2+0x3b>
callq 20146f <wrong_input>
201071: add $0x2,%rbx
cmp %rbp,%rbx
jne 201062 <func_2+0x2c>
Чтобы избежать этого первого callq
для неправильного ввода, первые 8 байтов в (%rsp)
должны быть:
%rsp %rbx
v v
00,00,00,00,01,00,00,00
-----------
+++++++++++ ===========
Но тогда первая итерация цикла завершится ошибкой и сделает вторую callq
неправильной_вводной, потому что:
----------- mov -0x2(%rbx),%eax --> 0x00010000
+++++++++++ add -0x4(%rbx),%eax --> 0x00010000 + 0x00000000
=========== cmp %eax,(%rbx) --> 0x00010000 <> 0x00000001
Если мы рассмотрим только часть цикла, то сможем найти последовательность целых чисел, которая пройдет. Вот они:
65536, 131073, 327683, 851976, 2228245, 5832759, 144
Вам нужно посмотреть на это при сохранении в памяти:
first last
%rsp %rbx --> %rbx %rbp
v v v v
00,00,01,00,01,00,02,00,03,00,05,00,08,00,0D,00,15,00,22,00,37,00,59,00,90,00
----------- -----------
+++++++++++ =========== +++++++++++ ===========
Обратите внимание, что цикл считывает одно слово после конца в %rbp
, поэтому ввод на самом деле представляет собой шесть с половиной целых чисел двойного слова!
@NoobCoder Поскольку это инструкция LEA
, сам адрес хранится в регистре %RBX
. Никакой загрузки из памяти! Если %RSP
равно 0x2020, то %RBX
получает только значение 0x2024.
Что вы подразумеваете под «истинный адрес становится значением»? Я не могу понять, что делает "lea 0x4(%rsp),%rbx". Он идет по адресу RSP, добавляет 4, затем переходит на новый адрес и получает его значение внутри RBX? или он фактически помещает адрес, например «0x0120» внутри RBX, в качестве значения?
да я знаю, что это цель LEA. А как же мов? Как вы упомянули в своем примере. Будет ли он перемещать значение внутри адреса?
@NoobCoder Инструкция, в которой используются круглые скобки, относится к некоторой ячейке памяти. Как только все компоненты адреса собраны вместе, мы получаем истинный адрес. Затем вступает в действие инструкция. Если это LEA
, мы просто используем значение адреса, если это MOV
, мы читаем или записываем что-то из или в память.
@NoobCoder В вашем фрагменте кода нет цикла! Для этого вам понадобится какая-то инструкция перехода, скорее всего, условный переход ниже инструкции CMP
.
да, у меня есть условный переход, я просто не написал его здесь. Мне все еще довольно сложно понять, что делает этот цикл. Я имею в виду, что я всегда пытаюсь сравнить его с другим языком, таким как C или JAVA, и «перевести» его, но я не могу понять, что здесь происходит. Он сразу возвращается к -0x2(%rbx),%eax
@NoobCoder Разве перед этим фрагментом не было push %rbp
?
Я добавил полный код. Моя цель здесь - найти правильный ввод (6 целых чисел). Я обнаружил, что первый должен быть «1», потому что первый CMP равен 0x1. Но потом он начинает зацикливаться, и я не могу найти формулу, по которой он работает.
по теме: Пара вопросов про [база + индекс*шкала + дисп] / Как работает "mov (%ebx,%eax,4),%eax"? / Использование LEA для значений, которые не являются адресами/указателями? описывает использование LEA для простой математики.