Assembly 为什么在64位程序中%esp和%ebp的寄存器值总是负值?

Assembly 为什么在64位程序中%esp和%ebp的寄存器值总是负值?,assembly,x86,64-bit,gnu-assembler,Assembly,X86,64 Bit,Gnu Assembler,这是一个GNU汇编程序 .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 #p

这是一个GNU汇编程序


.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
当添加
.code32
指令时,可以遵守该指令

$ as -g hello.s -o hello.o
$ ld hello.o -o hello
但是,在运行时,它总是显示“段故障”

我发现当使用GDB进入
power
时,%esp和%ebp的寄存器总是负值

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) 
我怎样才能解决这个问题。我的操作系统是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

因为Linux将用户空间堆栈指针放在虚拟地址空间的顶部附近,虚拟地址空间靠近4GiB区域的顶部,32位进程可以在64位内核下使用4GiB区域。通常,您希望以十六进制打印指针,如
p/x$ebp
。这不是您需要解决的问题(除了您选择将它们打印为带符号的十进制数)。哦,等等,
.code32
不会生成32位进程,它只允许您将32位机器代码放入一个可执行文件中,该可执行文件仍会将其解码为64位;幸运的是,它没有中断(任何涉及符号的寻址模式,或寄存器的inc/dec,或任何假定
push
会将ESP移动4而不是8的寻址模式),当然
push
pop
,或
call
会在
sub$4,%ESP
将RSP截断为32位ESP后发生故障。