Я очень новичок в сборке, и у меня проблемы с переводом кодов друг в друга. Может ли кто-нибудь помочь мне найти ответ?
sumAndProd(int, int):
pushq %rbp
movq %rsp, %rbp
movl %edi, -20(%rbp)
movl %esi, -24(%rbp)
movl -20(%rbp), %edx
movl -24(%rbp), %eax
addl %edx, %eax
movl %eax, -4(%rbp)
movl -20(%rbp), %eax
imull -24(%rbp), %eax
movl %eax, -8(%rbp)
movl -4(%rbp), %eax
cmpl -8(%rbp), %eax
jle .L2
movl -4(%rbp), %eax
jmp .L3
.L2:
movl -8(%rbp), %eax
.L3:
popq %rbp
ret
Я постараюсь изо всех сил, но перевод с ассемблера на C очень сложен.
Во-первых, я прокомментировал, что делает каждая из инструкций. Извините, мне пришлось сначала преобразовать его в синтаксис Intel.
push rbp
mov rbp,rsp
mov DWORD PTR [rbp-0x14],edi ; this places the first argument (int) to some arbitirary location
mov DWORD PTR [rbp-0x18],esi ; does the same for the second argument
mov edx, DWORD PTR [rbp-0x14] ; puts the first argument to edx from the place that it was stored before
mov eax, DWORD PTR [rbp-0x18] ; puts the second argument to eax
add eax,edx ; add them
mov DWORD PTR [rbp-0x4], eax ; store the sum somewhere
mov eax, DWORD PTR [rbp-0x14] ; move the first argument back into eax
imul eax, DWORD PTR [rbp-0x18] ; multiply first argument with the second argument
mov DWORD PTR [rbp-0x8],eax ; store the product somewhere
mov eax, DWORD PTR [rbp-0x4] ; get the sum into eax
cmp eax, DWORD PTR [rbp-0x8] ; compare the sum with the product
jle .L2 ; if sum is less than or equal to product go to L2
mov eax, DWORD PTR [rbp-0x4] ; else put sum in eax
jmp .L3 ; return sum
.L2:
mov eax, DWORD PTR [rbp-0x8] ; put the product to eax and return product
.L3:
pop rbp ; clear stack
ret ; return eax
Затем давайте переведем это в код C:
int sumAndProd(int a, int b)
{
int sum = a + b;
int product = a * b;
if(sum <= product)
{
return product;
}
else
{
return sum;
}
}
Это было бы моим лучшим предположением.
Обновлено: эти дополнительные переменные c и d действительно были избыточными. Когда вы компилируете код без них с помощью GCC и дизассемблируете с помощью objdump, вы получаете следующий вывод:
0000000000000000 <sumAndProd>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 89 7d ec mov %edi,-0x14(%rbp)
7: 89 75 e8 mov %esi,-0x18(%rbp)
a: 8b 55 ec mov -0x14(%rbp),%edx
d: 8b 45 e8 mov -0x18(%rbp),%eax
10: 01 d0 add %edx,%eax
12: 89 45 fc mov %eax,-0x4(%rbp)
15: 8b 45 ec mov -0x14(%rbp),%eax
18: 0f af 45 e8 imul -0x18(%rbp),%eax
1c: 89 45 f8 mov %eax,-0x8(%rbp)
1f: 8b 45 fc mov -0x4(%rbp),%eax
22: 3b 45 f8 cmp -0x8(%rbp),%eax
25: 7f 05 jg 2c <sumAndProd+0x2c>
27: 8b 45 f8 mov -0x8(%rbp),%eax
2a: eb 03 jmp 2f <sumAndProd+0x2f>
2c: 8b 45 fc mov -0x4(%rbp),%eax
2f: 5d pop %rbp
30: c3 retq
Это точно соответствует исходному коду сборки (по крайней мере, я так думаю).
@TahaYasinErel добавил правку.
Re: ваши «дополнительные переменные c и d» - то, что вы видите, это неоптимизированная сборка, сохраняющая входящие аргументы регистра в стек, по причинам отладки / Переполнение регистра аргументов gcc на x86-64. В C каждая переменная имеет адрес, включая аргументы функций, и отладочная сборка не использует свободу правила «как если» для оптимизации этого. См. также Как удалить «шум» из вывода сборки GCC/clang?
Эта функция, конечно, намного проще, если скомпилирована с оптимизацией: godbolt.org/z/GosjoxY1v
@PeterCordes да, я был сбит с толку, когда впервые прочитал это, не было никакого смысла снова сохранять аргументы, и поэтому я предположил, что должны быть дополнительные переменные, тогда просто неоптимизированный код. Спасибо за разъяснение.
это не реверс-инжиниринг. Вы должны показать, что вы пробовали. В том же сообществе, что и stackoverflow, есть Разобрать механизм с целью понять, как это работает, но вам все равно нужно показать свои усилия, никто не решит за вас что-то бесплатно