简体   繁体   中英

NASM 32-bit: printing content of register by printf

I'm new to assembly. I'm having different output for following simple code from what I expected. each time before printf is called, content of eax is shifted to the right by some number. What am I doing wrong? Thanks.

Code:

;file name : testing.asm
;assemble and link with:
;nasm -f elf testing.asm && gcc -m32 -o testing testing.o
extern  printf      ; the C function, to be called

SECTION .data       ; Data section, initialized variables

    a:  dd  15  ; int a=15
    str:    db "content in eax=%d", 10, 0 

SECTION .text       ; Code section.

    global main     ; the standard gcc entry point
main:               ; the program label for the entry point
    mov     ebp, esp
    mov     eax, [a]    ; put a from store into register

    shr     eax, 1      ; eax content should be 15>>1 = 7
    push    eax     
    push    dword str   ; string to be printed
    call    printf      ; printf(str,content_of_eax)

    shr     eax, 2
    push    eax         ; eax content should be 7>>2 = 1
    push    dword str   
    call    printf      ; printf(str,content_of_eax)    

    shr     eax, 1  
    push    eax         ; eax content should be 1>>1 = 0
    push    dword str   
    call    printf      ; printf(str,content_of_eax)

    mov     esp, ebp    ; takedown stack frame
    mov     eax, 0      ; normal, no error, return value
    ret                 ; return

Output:

content in eax=7
content in eax=4
content in eax=8

Expected Output:

content in eax=7
content in eax=1
content in eax=0

printf returns its result in eax , the original value is lost.

You should reload it from [a] or use a register that is saved across function calls such as esi , but you should save it as well and restore it before returning to the caller. You should pop the arguments passed to printf with a add esp,8 after each call to keep your stack frame consistent.

In your data section you could just use an equate for a since you only use that variable once and do not change it (i'll call it value ).

    fmt db "content in eax=%d",0xa,0
    value equ 15

In the main function i'm pretty sure (correct me if i'm wrong) that you're supposed to save the base pointer before you update it with the stack pointer.

main:
        push ebp
        mov ebp, esp

Now you could create a local variable to store the current value you are working on.

sub esp, 4

From there you would just keep fetching, shifting and storing the value on the stack before each call to printf .

mov eax, value          ; move 15 into eax  
shr eax, 1              ; make first shift
mov dword[ebp-4], eax   ; store result in local variable

push eax                ; eax = 7
push fmt
call printf             
add esp, 8              ; clean eax & fmt off the stack

mov eax, [ebp-4]        ; fetch last shift result from variable
shr eax, 2              ; make second shift
mov dword[ebp-4], eax   ; store result back in variable

push eax                ; eax = 1
push fmt
call printf             
add esp, 8              

mov eax, [ebp-4]        ; fetch last shift result from variable
shr eax, 1              ; make last shift

push eax                ; eax = 0
push fmt
call printf             
add esp, 8

add esp, 4              ; clean local variable

And then remember, before you return, when you release the stack frame that you also restore (pop) the base pointer.

mov esp, ebp
pop ebp

This should output:

content in eax=7
content in eax=1
content in eax=0

Remember that printf will return the number of characters transmitted to the output. So when you do this:

call    printf      ; printf(str,content_of_eax)

shr     eax, 2

You are actually shifting the result from printf:

  • "content in eax=7\\n" is 17 characters, so shitfting by 2 gives: 17 / 4 = 4

You need to save the value (either in a preserved register, on the stack or in memory) before shifting.

This answer seems not to be a good solution, I'm currently keeping it because of the discussion below


Like others said, printf will return it's result to eax. The result of printf is the number of bytes written.

Since you pushed the result of the shr operation to the stack, you can retrieve them again using pop , like this:

shr     eax, 1      ; eax content should be 15>>1 = 7
push    eax    
push    dword str   ; string to be printed
call    printf      ; printf(str,content_of_eax)

pop     eax 
pop     eax 
shr     eax, 2
push    eax         ; eax content should be 7>>2 = 1
push    dword str   
call    printf      ; printf(str,content_of_eax)  

# and so on ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM