Utknąłem nauki podstawowe podstawy języka asemblera z Fahrenheita do przykładu Celsius z K & R książka. Oto kod C, które mam na myśli:Potrzebuję wyjaśnienia instrukcji montażu K & R fahr-to-cels przykład
#include <stdio.h>
main()
{
int fahr, celsius;
int lower, upper, step;
lower = 0;
upper = 300;
step = 20;
fahr = lower;
while (fahr <= upper) {
celsius = 5 * (fahr-32)/9;
printf("%d\t%d\n", fahr, celsius);
fahr = fahr + step;
}
}
Wraz z GCC 4.4.7 (GNU/Linux x86-64) pojawia się po demontażu:
$ gcc -O0 -g -ansi -pedantic l1-2a.c
$ gdb -q a.out
(gdb) disas /m main
(gdb) disas /m main
Dump of assembler code for function main:
6 {
0x00000000004004c4 <+0>: push %rbp
0x00000000004004c5 <+1>: mov %rsp,%rbp
0x00000000004004c8 <+4>: sub $0x20,%rsp
7 int fahr, celsius;
8 int lower, upper, step;
9
10 lower = 0;
0x00000000004004cc <+8>: movl $0x0,-0xc(%rbp)
11 upper = 300;
0x00000000004004d3 <+15>: movl $0x12c,-0x8(%rbp)
12 step = 20;
0x00000000004004da <+22>: movl $0x14,-0x4(%rbp)
13
14 fahr = lower;
0x00000000004004e1 <+29>: mov -0xc(%rbp),%eax
0x00000000004004e4 <+32>: mov %eax,-0x14(%rbp)
15 while (fahr <= upper) {
0x00000000004004e7 <+35>: jmp 0x400532 <main+110>
0x0000000000400532 <+110>: mov -0x14(%rbp),%eax
0x0000000000400535 <+113>: cmp -0x8(%rbp),%eax
0x0000000000400538 <+116>: jle 0x4004e9 <main+37>
16 celsius = 5 * (fahr-32)/9;
0x00000000004004e9 <+37>: mov -0x14(%rbp),%edx
0x00000000004004ec <+40>: mov %edx,%eax
0x00000000004004ee <+42>: shl $0x2,%eax
0x00000000004004f1 <+45>: add %edx,%eax
0x00000000004004f3 <+47>: lea -0xa0(%rax),%ecx
0x00000000004004f9 <+53>: mov $0x38e38e39,%edx
0x00000000004004fe <+58>: mov %ecx,%eax
0x0000000000400500 <+60>: imul %edx
0x0000000000400502 <+62>: sar %edx
0x0000000000400504 <+64>: mov %ecx,%eax
0x0000000000400506 <+66>: sar $0x1f,%eax
0x0000000000400509 <+69>: mov %edx,%ecx
0x000000000040050b <+71>: sub %eax,%ecx
0x000000000040050d <+73>: mov %ecx,%eax
0x000000000040050f <+75>: mov %eax,-0x10(%rbp)
17 printf("%d\t%d\n", fahr, celsius);
0x0000000000400512 <+78>: mov $0x400638,%eax
0x0000000000400517 <+83>: mov -0x10(%rbp),%edx
0x000000000040051a <+86>: mov -0x14(%rbp),%ecx
0x000000000040051d <+89>: mov %ecx,%esi
0x000000000040051f <+91>: mov %rax,%rdi
0x0000000000400522 <+94>: mov $0x0,%eax
0x0000000000400527 <+99>: callq 0x4003b8 <[email protected]>
18 fahr = fahr + step;
0x000000000040052c <+104>: mov -0x4(%rbp),%eax
0x000000000040052f <+107>: add %eax,-0x14(%rbp)
19 }
20 }
0x000000000040053a <+118>: leaveq
0x000000000040053b <+119>: retq
End of assembler dump.
Co nie jest oczywiste dla mnie jest ten fragment:
16 celsius = 5 * (fahr-32)/9;
0x00000000004004e9 <+37>: mov -0x14(%rbp),%edx
0x00000000004004ec <+40>: mov %edx,%eax
0x00000000004004ee <+42>: shl $0x2,%eax
0x00000000004004f1 <+45>: add %edx,%eax
0x00000000004004f3 <+47>: lea -0xa0(%rax),%ecx
0x00000000004004f9 <+53>: mov $0x38e38e39,%edx
0x00000000004004fe <+58>: mov %ecx,%eax
0x0000000000400500 <+60>: imul %edx
0x0000000000400502 <+62>: sar %edx
0x0000000000400504 <+64>: mov %ecx,%eax
0x0000000000400506 <+66>: sar $0x1f,%eax
0x0000000000400509 <+69>: mov %edx,%ecx
0x000000000040050b <+71>: sub %eax,%ecx
0x000000000040050d <+73>: mov %ecx,%eax
0x000000000040050f <+75>: mov %eax,-0x10(%rbp)
to znaczy, że wszystko rozumiem do:
lea -0xa0(%rax),%ecx
jak to jest odjęcie 160
z %eax
rejestru, który przechowuje 5*fahr
, jak:
5 * (fahr-32)/9 <=> (5*fahr - 5*32)/9 <=> (5*fahr - 160)/9
więc po %ecx
(jak również kompletnych %rcx
) przechowuje 5*fahr - 160
. Jednak nie wiem jak to jest dzielić przez 9 wtedy. Wydaje się, że niektóre sztuczki, takie jak "pomnóż przez odwrotność", aby uniknąć podziału, ale nie rozumiem, jak to działa.
To jest tak zwany podział liczb magicznych. Zobacz [tutaj] (http://ridiculousfish.com/blog/posts/labor-of-division-episode-i.html), aby uzyskać opis. – Jester
'0x38e38e39' = 2^33/9. –
Próba poznania złożenia przez obserwację zespołu generowanego przez kompilator jest prawdopodobnie złym pomysłem, poza tym, aby dowiedzieć się, że kompilator prawdopodobnie zrobi to lepiej, niż można na wszystkie sposoby zaakceptować czytelność! – Clifford