Oczywiście w starym sofcie nie ma totalnie nic złego. Oprócz niepoprawionych błędów, i brakującej funkcjonalności.
Pomijając już problemy z .fill, .string czy .ascii, czy też aliasami pewnych instrukcji, to najbardziej zaskoczył nas LOOP oraz LOOPNE.
Otóż okazało się że owszem, ten mnemonik jest obsługiwany. I w małych programikach działa nawet poprawnie. Niestety, przy większym assemblerowym projekcie okazało się że argument loop jest źle tłumaczony. Rzućmy okiem na przykład.
Źródło (składnia AT&T):
jump_f09d4:
mov (%edi),%al
mov (%eax,%esi,1),%bl
mov %bl,(%edi)
add $0x1,%edi
loop jump_f09d4
jmp jump_f0a0b
Plik wynikowy:
(gdb) x/10i $eip
0xe318a <jump_f09d4>: mov (%edi),%al
0xe318c <jump_f09d4+2>: mov (%eax,%esi,1),%bl
0xe318f <jump_f09d4+5>: mov %bl,(%edi)
0xe3191 <jump_f09d4+7>: add $0x1,%edi
0xe3194 <jump_f09d4+10>: loop 0xe3187 <jump_f09bb+26>
0xe3196 <jump_f09d4+12>: jmp 0xe31cb <jump_f0a0b>
Jak widać, loop w pliku wynikowym powinien skakać do 0xe318a, a skacze do 0xe3187, czyli 3 bajty za wcześnie. I co ciekawe, zawsze były to właśnie 3 bajty. Wygląda na to, że assembler stwierdził że instrukcja loop nagle zamiast opcode + 1 bajt argumentu (2 bajty), ma opcode + 4 bajty argumentu (5 bajtów), i traktował pozycje wyjściową skoku jako eip+5 zamiast prawidłowo eip+2. No i się zrobiły 3 bajty różnicy. LOOPNE zachowywało się tak samo. Natomiast LOOPE nie mieliśmy nigdzie w kodzie ;>
Problem został rozwiązany poprzez zastąpienie LOOP kodem równoważnym:
sub $0x1,%ecx
jnz ETYKIETA
Natomiast LOOPNE zostało zastąpione przez:
jz 0f
sub $0x1,%ecx
jnz ETYKIETA
jmp 1f
0:sub $0x1,%ecx
1:
No i wszystko nagle zaczęło działać.
Oby Apple jednak kiedyś zdecydowało się na upgrade assemblera ;D
Comments:
ale postanowiłem się przywitać, pamiętasz mnie jeszcze? :)
Sure że Cię pamiętam ;>>>
Kurcze, nawet nie wiedziałem że masz nowego bloga, i to widzę że bardzo ciekawego, super ;> RSS++
Thx za odwiedziny ;>
Add a comment: