Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
598 views
in Technique[技术] by (71.8m points)

x86 - Write a Fizz program in assembly / Using C library

Could someone help me with this assembly program: First print out numbers 1 to 100. Then follow the rules for the children's counting game Fizz: whenever the number is evenly divisible by 5, or contains the digit 5, replace the number by the word “Fizz”. This is my program so far:

extern printf
section .data
msg db "Hello, world!",0xa
len equ $ - msg
fmt: db "a=%d, eax=%d", 10, 0 ; The printf format, "
",'0'
section .text
global main
main:
L1:
    mov eax,1
    push eax
    call printf
    cmp eax,100
    jae end
    inc eax
end:
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I'm not going to give you a complete answer since this appears to be homework. I'll provide enough to get you started. The following code will simply count from 1 to 100:

extern printf
section .data
fmt: db "number = %d", 10, 0 ; printf format string

section .text
global main
main:
    push ebx      ; EBX is callee saved so we need to save it so that it 
                  ;     can be restored when we RETurn from main
    mov ebx, 1    ; ebx = 1 (counter)
L1:
    push ebx      ; 2nd parameter is our number(counter) to print
    push fmt      ; 1st parameter is the address of the format string
    call printf
    add sp, 8     ; We pushed 8 bytes prior to printf call, we must adjust the stack
                  ;     by effectively removing those bytes.
    inc ebx       ; counter += 1
    cmp ebx,100
    jle L1        ; If counter is <= 100 go back and print again
end:
    xor eax,eax   ; Return 0 when our program exits
    pop ebx       ; Restore EBX before exiting main per calling convention
    ret           ; RETurn from main will cause program to gracefully exit
                  ;     because we are linked to the C runtime code and main was 
                  ;     called by that C runtime code when our program started. 

Primary changes from your code. We display the number using printf with a proper format string. I put the counter in EBX because you must be aware that EAX, ECX, and EDX are not preserved across a function call using CDECL calling convention:

In cdecl, subroutine arguments are passed on the stack. Integer values and memory addresses are returned in the EAX register, floating point values in the ST0 x87 register. Registers EAX, ECX, and EDX are caller-saved, and the rest are callee-saved.

[snip]

The caller cleans the stack after the function call returns.

After making CDECL function calls, we must restore the stack pointer. We push 2 DWORDs (a total of 8 bytes) as parameters to printf therefore we must add 8 to the stack pointer to effectively remove them when the function returns.

The highlighted sentence is important. To simplify things I use EBX because its value is preserved across function calls and we don't have to save and restore it around the function calls we make (like printf).

Since main is being called as a C function using CDECL calling convention, we must preserve any callee registers (registers our function must preserve) so that we don't cause undefined behavior in the C library code that calls main. EBX is a callee saved register we did modify, so we use PUSH/POP around our function so that EBX is preserved when our main function returns.

The program has to be linked to a C library. The easiest way to do this is to link with GCC. The compile and link stage could look like:

nasm -f elf32 count100.asm -o count100.o
gcc -m32 count100.o -o count100 

This should assemble and link your code to a 32-bit program called count100 that can be executed with this command:

./count100

I leave the rest of the assignment up to you.


The assembly code in the sample would be equivalent to this code in C:

#include <stdio.h>

int main()
{
    int counter = 1;
    do {
        printf ("number = %d
", counter);
    } while (++counter <= 100);

    return 0;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...