0

This is a GNU-Assembly program.


.code32               #must add this line, otherwise, this program can't be complied.
.section .data

.section .text

.global _start
_start:
    pushl   $3                      #push second argument
    pushl   $2                      #push first argument
    call    power                   #call the function
    addl    $8, %esp                #move the stack pointer back
    
    pushl   %eax                    #save the first answer before calling the next function
    
    pushl   $2                      #push second argument
    pushl   $5                      #push first argument
    call    power                   #call the function
    addl    $8, %esp                #move the stack pointer back
    
    #The second answer is already
    #in %eax. We saved the
    #first answer onto the stack,
    #so now we can just pop it
    #out into %ebx

    popl    %ebx    
    
    addl    %eax, %ebx            #add them together
    
    movl    $1, %eax              #exit (%ebx is returned)
    int     $0x80
    
.type power, @function
#first arg-> base number
#second arg-> the power to raise
power:
    pushl   %ebp                #save old base pointer
    movl    %esp, %ebp          #make stack pointer the base pointer
    subl    $4, %esp            #get room for our local storage
    
    movl    8(%ebp), %ebx   
    movl    12(%ebp), %ecx  
    

    movl    %ebx, -4(%ebp)  
    
    power_loop_start:
    cmpl    $1, %ecx
    je  end_power   
    movl    -4(%ebp), %eax
    imull   %ebx, %eax  
    movl    %eax, -4(%ebp)
    decl    %ecx
    jmp power_loop_start
    
    end_power:
    movl    -4(%ebp), %eax  
    movl    %ebp,   %esp    
    popl    %ebp    
    ret

It can be complied when added the .code32 instruction.

$ as -g hello.s -o hello.o
$ ld hello.o -o hello

However, it always shows "segment fault" when run it.

I find that the registers of %esp and %ebp is always negative when step into power using GDB.

Breakpoint 1, _start () at hello.s:9
9       pushl   $3
(gdb) n
_start () at hello.s:10
10      pushl   $2
(gdb) 
_start () at hello.s:11
11      call    power
(gdb) s
power () at hello.s:35
35      pushl   %ebp 
(gdb) n
36      movl    %esp, %ebp 
(gdb) 
37      subl    $4, %esp    
(gdb) n
power () at hello.s:45
45      movl    8(%ebp), %ebx   
(gdb) print $ebp
$1 = -8144
(gdb) print $esp
$2 = -8148
(gdb) 

How can I solve this problem. My OS is Ubuntu.

Linux locomotive-VirtualBox 5.4.0-52-generic #57~18.04.1-Ubuntu SMP Thu Oct 15 14:04:49 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Land
  • 171
  • 11
  • Because Linux puts the user-space stack pointer near the top of virtual address space, which is near the top of the 4GiB region that 32-bit processes can use under 64-bit kernels. Normally you'd want to print pointers in hex, like `p /x $ebp`. It's not a problem you need to solve (except for your choice to print them as signed decimal). – Peter Cordes Nov 07 '20 at 06:16
  • 4
    Oh wait, `.code32` does *not* make a 32-bit process, it just lets you put 32-bit machine code into an executable that will still decode it as 64-bit; You're just lucky it happened not to break (any addressing mode involving a symbol, or inc/dec of a register, or anything that assumed `push` would move ESP by 4 not 8.) [Assembling 32-bit binaries on a 64-bit system (GNU toolchain)](https://stackoverflow.com/q/36861903) – Peter Cordes Nov 07 '20 at 06:19
  • And of course `push`, `pop`, or `call` would segfault after `sub $4, %esp` truncates RSP to 32-bit ESP. – Peter Cordes Nov 07 '20 at 06:27

0 Answers0