x86 32 bit makine kodu, 24 21 bayt
changelog: -3 bytes: @peter ferrie tarafından standart add / cmp / jbe / add'i bir DAS hack'iyle değiştirin
64 bit: hala 24 bayt. Uzun mod, DAS op kodunu kaldırdı.
16 bit modu: varsayılan işlenen boyutu 16 bittir, ancak sorun özelliği doğal olarak 32 bittir. Sabit kodlu 8 onaltılık basamak dahil.
İle bayt ters bswapstandart amacıyla daha sonra elle int-> hex (en anlamlı yarım bayt ilk artan bir karakter çıkış tamponu hex basamak yazma.), Bir baytlık ve içinde yarım bayt arasında geçiş sırasına döngü göz önüne sermek için ihtiyaç duyan bu önüne geçilmesini bayt boyunca.
void lehex(char buf[8] /*edi*/, uint32_t x /*esi*/);64 bit modunda çalışmadığı sürece x86-64 System V gibi çağrılabilir . (EDI için çıkış işaretçisine ihtiyaç duyar stosb. Giriş numarası ECX veya EAX dışında herhangi bir kayıtta olabilir.)
1 lehex:
2 00000000 0FCE bswap esi
3 00000002 6A08 push 8 ; 8 hex digits
4 00000004 59 pop ecx
5 .loop: ;do{
6 00000005 C1C604 rol esi, 4 ; rotate high nibble to the bottom
7
8 00000008 89F0 mov eax, esi
9 0000000A 240F and al, 0x0f ; isolate low nibble
10 0000000C 3C0A cmp al, 10 ; set CF according to digit <= 9
11 0000000E 1C69 sbb al, 0x69 ; read CF, set CF and conditionally set AF
12 00000010 2F das ; magic, which happens to work
13
14 00000011 AA stosb ; *edi++ = al
15 00000012 E2F1 loop .loop ; }while(--ecx)
16
17 00000014 C3 ret
boyut = 0x15 = 21 bayt.
TIO FASM 32 bit x86 test durumu , write2 dizgiyi bir tampona eklemek için iki kez çağırdıktan sonra çıkışı yazmak için sistem çağrısı kullanan bir asm arayanı ile . Sayı ile harf arasındaki sınırda 9 ve A dahil olmak üzere 0..F tüm onaltılık basamakları test eder.
DASHack - x86 düşük dişlemesini dışarı taşınması için, yarım taşıma bayrağı vardır. İki 2 basamaklı BCD tamsayısının çıkarılmasından sonra kullanılması amaçlanan DAS talimatı gibi paketlenmiş BCD şeyler için kullanışlıdır. AL'nin düşük nibble'ı 0-9 aralığının dışında olduğunda, kesinlikle burada kötüye kullanıyoruz.
Kılavuzdaki Çalıştırma bölümünün if (old_AL > 99H) or (old_CF = 1)THEN AL ← AL − 60H;kısmına dikkat edin ; sbb her zaman CF'yi ayarlar, böylece kısım her zaman olur. Bu ve büyük harfler için ASCII aralığı,sub al, 0x69
cmp 0xD, 0xA CF ayarlamıyor
- sbb
0xD - 0x69AL = 0xA4'ye girdi olarak DAS'a girdi. (Ve CF'yi ayarlar, AF'yi temizler)
- DAS'ın ilk bölümünde AL - = 6 yok (çünkü 4> 9 yanlış ve AF = 0)
- AL - = 0x60 ikinci bölümde,
0x44ASCII kodunu'D'
bir sayıya karşı:
cmp 0x3, 0xA CF setleri
- sbb
3 - 0x69 - 1= AL = 0x99 ve CF ve AF'yi ayarlar
- DAS'ın ilk bölümünde AL - = 6 yok (9> 9 yanlış ama AF ayarlanmış), 0x93 bırakarak
- AL - = 0x60 ikinci bölümde, 0x33, ASCII kodu için bırakılır
'3'.
SBB'den çıkarma 0x6a, her sayı için <= 9 AF ayarlayacaktır, böylece tüm sayılar aynı mantığı izler. Ve her alfabetik onaltılık basamak için boş bırakın. yani DAS'ın 9 / A ayrık kullanımından doğru bir şekilde yararlanmak.
Normalde (performans için) skaler döngü için bir arama tablosu veya muhtemelen dalsız 2x leave cmp/cmovkoşullu ekleme kullanırsınız. Ancak 2 baytlık al, imm8talimatlar, kod boyutu için büyük bir kazançtır.
x86-64 sürüm sürümü : and al, 0xfve arasında sadece farklı olan bölüm stosb.
;; x86-64 int -> hex in 8 bytes
10 0000000C 0430 add al, '0'
11 0000000E 3C39 cmp al, '9'
12 00000010 7602 jbe .digit
13 00000012 0427 add al, 'a'-10 - '0' ; al = al>9 ? al+'a'-10 : al+'0'
14 .digit:
Bildirim o add al, '0' zaman çalışır ve koşullu eklenti sadece arasındaki farkı ekler 'a'-10ve '0'sadece bir bunu yapmak için, ifyerine if/ ' else.
Test edilmiş ve çalışır, Cmain yanıtımla aynı arayanı kullanır ve kullanır .char buf[8]printf("%.8s\n", buf)