2008-08-21 22 views
7

Bu biraz gariptir, ancak bugün GNU assembler'la (en azından sözdizimini okuyabilmek istiyorum) etrafa dolanıp, bu küçük örneklemi elde etmeye çalışıyordum. benim çalışmam Yani sadece 0'dan 100'e gitmek istiyorum, tüm zamanları basıyorum. Bu yüzden birkaç dakika sonra ben böyle bir cevap:Montaj dilinde 0'dan 100'e artırılıyor

# count.s: print the numbers from 0 to 100. 
    .text 
string: .asciz "%d\n" 
    .globl _main 

_main: 
    movl $0, %eax # The starting point/current value. 
    movl $100, %ebx # The ending point. 

_loop: 
    # Display the current value. 
    pushl %eax 
    pushl $string 
    call  _printf 
    addl  $8, %esp 

    # Check against the ending value. 
    cmpl %eax, %ebx 
    je _end 

    # Increment the current value. 
    incl %eax 
    jmp _loop 

_end: 

Bunu aldığım tüm 3 tekrar tekrar basılmış ve olduğunu. Söylediğim gibi, sadece küçük bir örnek, bu yüzden bu konuda fazla endişelenme, hayat ya da ölüm problemi değil.

(Biçimlendirme biraz bozuk, ancak önemli değil).

+2

'xorl% eax% eax' $ 0,% eax' movl' tamamen eşdeğerdir ve 3 bayt az sürer. Sadece söylüyorum. :) –

cevap

12

Herhangi bir yordamın kayıt defterlerinden herhangi birine yaptıklarına güvenemezsiniz. Kayıtları yığının üzerine itin ve printf çağırdıktan sonra geri alın veya bellekte tutulan artış ve son nokta değerlerine sahip olun ve gerektiğinde yazmaçlara okuyup yazabilirsiniz.

Umarım aşağıdaki işler. Bu itme gücünün eşdeğer bir popl olduğunu ve yığının üstüne fazla sayıda sayı atabileceğinizi farz ediyorum.

# count.s: print the numbers from 0 to 100. 
    .text 
string: .asciz "%d\n" 
    .globl _main 

_main: 
    movl $0, %eax # The starting point/current value. 
    movl $100,  %ebx # The ending point. 

_loop: 
    # Remember your registers. 
    pushl %eax 
    pushl %ebx 

    # Display the current value. 
    pushl %eax 
    pushl $string 
    call  _printf 
    addl  $8, %esp 

    # reinstate registers. 
    popl %ebx 
    popl %eax 

    # Check against the ending value. 
    cmpl %eax, %ebx 
    je _end 

    # Increment the current value. 
    incl %eax 
    jmp _loop 

_end: 
+1

btw - pusha ve popa tüm kayıtları itecek ve hepsini patlatacak .. Ben geçmişte oldukça kullanışlı buldum – warren

+0

Aşağıdaki notlardan. Dikkat edilmesi gereken şey ... "@seanyboy, senin çözümün çok fazla. Gerekli olan tek şey eax'i ecx gibi başka bir kayıtla değiştirmek." – seanyboy

+0

@warren - "pusha" ve "popa", 64-bit modunda desteklenmiyor. –

6

_printf ile aşina değilim ama eax'i değiştirebilir mi? Printf, yazdırılan karakter sayısını döndürmelidir, bu durumda bu iki: '0' ve '\ n'. Ben bunu eax olarak döndürdüğünü düşünüyorum ve bunu artırdığınızda, 3'ü elde edersiniz, yazdırmaya devam ettiğiniz şey budur. Sayaç için farklı bir kayıt kullanmanız daha iyi olabilir.

1

Nathan doğru yolda. Bir alt yordam çağrıldıktan sonra kayıt değerlerinin değiştirilemeyeceğini kabul edemezsiniz. Aslında, bunların değiştirileceğini varsaymak en iyisidir, aksi takdirde altprogram bu işi yapamazdı (en azından x86 gibi düşük kayıt sayısı mimarileri için). Bir değeri korumak istiyorsanız, onu bellekte saklamanız gerekir (örneğin, yığının üzerine koyun ve bulunduğu yeri takip edin).

Sahip olduğunuz diğer değişkenler için de aynısını yapmanız gerekir. Yerel değişkenleri saklamak için kayıtların kullanılması, mimariyi desteklemek için yeterli yazmaçlarla oldukça fazla ayrılmıştır (örn. EPIC, amd64, vb.)

3

İyi yazılan işlevler, genellikle tüm kayıtları yığının üzerine doğru iter ve Fonksiyon sırasında değişmeden kalacaktır. İstisna, dönüş değerini içeren eax olacaktır. Printf gibi kütüphane işlevleri büyük olasılıkla bu şekilde yazılır, bu nedenle Wedge'ın önerdiği gibi yapmam.:

Aynısını, sahip olduğunuz diğer değişkenler için yapmanız gerekir. Yerel değişkenler depolamak için kayıtlar kullanılarak hemen hemen bildiklerimi, derleyiciler genellikle işlevlerini derlemek dan (örn EPIC, amd64, vs.) Aslında

, tam olarak başa bu şekilde desteklemek için yeterli kayıtları ile mimarileri için ayrılmıştır bu konuyla.

@seanyboy, çözümünüz aşırı. İhtiyacın olan tek şey, eax'ı ecx gibi başka bir kayıtla değiştirmek.

-1

Örneğin, %ebp gibi değişecekleri varsayımları kullanmak için yeniden yazabilirsiniz. Sadece onları başlangıçta yığınının üstüne bastığınızdan ve rutininizin sonunda onları çıkardığınızdan emin olun.

# count.s: print the numbers from 0 to 100. 
    .text 
string: .asciz "%d\n" 
    .globl _main 

_main: 
    push %ecx 
    push %ebp 
    movl $0, %ecx # The starting point/current value. 
    movl $100,  %ebp # The ending point. 

_loop: 
    # Display the current value. 
    pushl %ecx 
    pushl $string 
    call  _printf 
    addl  $8, %esp 

    # Check against the ending value. 
    cmpl %ecx, %ebp 
    je _end 

    # Increment the current value. 
    incl %ecx 
    jmp _loop 

_end: 
    pop  %ebp 
    pop  %ecx 
5

"Kendinizi kurtarmadan" kaydedilen kayıtları kendiniz kaydetmek zorunda kalmadan güvenle kullanabilirsiniz. X86'da bunlar edi, esi ve ebx; diğer mimariler daha var.

Bu ABI referanslarda belgelenen: http://math-atlas.sourceforge.net/devel/assembly/