运行出现Segmentation fault问题

unixplus 2014-04-19 10:17:07
这是一个简单的输出“hello world”的汇编程序
我的平台
$uname -a
Linux www 2.6.32-431.11.2.el6.x86_64 #1 SMP Tue Mar 25 19:59:55 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux


.code32
.section .data
output:
.asciz "hello world.\n"
.section .text
.globl main
main:
nop
pushl $output
call printf
popl %eax

pushl $0
call exit

编译链接都问题。运行时出现Segmentation fault错误
调试发现错误在调用printff时,收到了SIGSEGV(无效内存引用)的信号
请问这是什么原因呢?
...全文
862 38 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
38 条回复
切换为时间正序
请发表友善的回复…
发表回复
unixplus 2014-05-08
  • 打赏
  • 举报
回复
引用 37 楼 DelphiGuy 的回复:
loop指令有-128~127字节的转移范围限制,指令本身的延迟长一些,吞吐量低,如果循环体太小的话(比如6条指令以内),最好不要用loop,不过它和jmp指令一样分支预测的命中率可以达到100%(指令执行之前就可以知道转移目标地址),而条件转移指令的分支预测是不可能达到100%的,不过条件转移指令使用上更灵活,有很多种条件可选。
严重受教!感谢再次的回答。
  • 打赏
  • 举报
回复
loop指令有-128~127字节的转移范围限制,指令本身的延迟长一些,吞吐量低,如果循环体太小的话(比如6条指令以内),最好不要用loop,不过它和jmp指令一样分支预测的命中率可以达到100%(指令执行之前就可以知道转移目标地址),而条件转移指令的分支预测是不可能达到100%的,不过条件转移指令使用上更灵活,有很多种条件可选。
unixplus 2014-05-07
  • 打赏
  • 举报
回复
引用 35 楼 DelphiGuy 的回复:
你说的“循环和跳转”是指什么呢?loop指令和jmp指令吗?
是的,loop指令和条件&非条件跳转指令
  • 打赏
  • 举报
回复
你说的“循环和跳转”是指什么呢?loop指令和jmp指令吗?
  • 打赏
  • 举报
回复
简单浮点运算使用SSE指令速度更快,不过精度比不上FPU(比如sqrtss/sqrtsd/sqrtps/sqrtpd相比fsqrt),也不支持超越函数。
unixplus 2014-05-05
  • 打赏
  • 举报
回复
引用 31 楼 DelphiGuy 的回复:
我也是在交流中学习。在我看来,RAX指示传入参数使用向量寄存器的数量这个设计没啥意义,win64 ABI中就没这个东西,当然也可能是我理解不够。
说不定有这个东西就免去了运行时不得不去检查是否有浮点值传入的麻烦呢。。。我发现个事情,我用C写的涉及浮点运算的代码汇编出来后发现使用的是SSE来运算浮点运算,为什么不是用FPU呢?SSE更快吗?但是简单的浮点运算使用128位的xmm寄存器不是太浪费资源了吗
unixplus 2014-05-05
  • 打赏
  • 举报
回复
引用 33 楼 DelphiGuy 的回复:
简单浮点运算使用SSE指令速度更快,不过精度比不上FPU(比如sqrtss/sqrtsd/sqrtps/sqrtpd相比fsqrt),也不支持超越函数。
这样啊! 那再请教一个问题,循环和跳转哪个效率更高呢?
  • 打赏
  • 举报
回复
我也是在交流中学习。在我看来,RAX指示传入参数使用向量寄存器的数量这个设计没啥意义,win64 ABI中就没这个东西,当然也可能是我理解不够。
unixplus 2014-04-30
  • 打赏
  • 举报
回复
引用 28 楼 DelphiGuy 的回复:
在System V x64 ABI,RAX指示传入参数使用向量寄存器(对于x64就是MMX/SSEn寄存器)的数量,对于楼主调用printf的例子,没有浮点参数传入,所以就movl $0, %eax了。
果然如此啊!那是不是每个函数都需要指明rax的值呢前辈果然厉害
unixplus 2014-04-30
  • 打赏
  • 举报
回复
今天我试了一下内联汇编,查看汇编出来的代码的时候发现在call printf之前有一条不知何目的的movl $0, %eax的语句, 于是我又试了hello world程序

.section .data
string:
    .asciz "hello, world\n"
.section .text
.globl _start
_start:
    nop
    movl $string, %edi
    movl $0, %eax
    call printf

    movl $60, %eax
    movl %eax, %ebx
    syscall

以上代码输出正确,链接的是64位的库 如果我把call printf前的movl $0, %eax删除的话,就会出现段错误。不知这个movl $0, %eax是个什么作用呢?它又不是作为printf的参数。 System V AMD64 ABI The calling convention of the System V AMD64 ABI[11] is followed on Solaris, GNU/Linux, FreeBSD, Mac OS X, and other UNIX-like or POSIX-compliant operating systems. The first six integer or pointer arguments are passed in registers RDI, RSI, RDX, RCX, R8, and R9, while XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 and XMM7 are used for floating point arguments. For system calls, R10 is used instead of RCX
unixplus 2014-04-30
  • 打赏
  • 举报
回复
引用 23 楼 DelphiGuy 的回复:
你可以连接到libc.so试试,用的库是libc.a。
今天我试了一下内联汇编,查看汇编出来的代码的时候发现在call printf之前有一条不知何目的的movl $0, %eax的语句, 于是我又试了hello world程序

.section .data
string:
    .asciz "hello, world\n"
.section .text
.globl _start
_start:
    nop
    movl $string, %edi
    movl $0, %eax
    call printf

    movl $60, %eax
    movl %eax, %ebx
    syscall

以上代码输出正确,链接的是64位的库 如果我把call printf前的movl $0, %eax删除的话,就会出现段错误。不知这个movl $0, %eax是个什么作用呢?它又不是作为printf的参数。 System V AMD64 ABI The calling convention of the System V AMD64 ABI[11] is followed on Solaris, GNU/Linux, FreeBSD, Mac OS X, and other UNIX-like or POSIX-compliant operating systems. The first six integer or pointer arguments are passed in registers RDI, RSI, RDX, RCX, R8, and R9, while XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 and XMM7 are used for floating point arguments. For system calls, R10 is used instead of RCX
unixplus 2014-04-30
  • 打赏
  • 举报
回复
引用 26 楼 fhqdx0012 的回复:
你自己看下 printf函数内部 看看eax是不是参数!把反汇编的代码贴上来 没你那个环境不好为你分析
改成25楼的写法后就没有问题了 下面的代码是有问题时候的代码:

[feng@www Assembly]$ cat he.s 
.code32
.section .data
    output:
        .asciz "hello world!\n"
.section .text
.globl _start
_start:
    nop
    pushl $output
    call printf

    movl $1, %eax
    movl $0, %ebx
    int $0x80
编译&链接: $ as -gstabs he.s -o he.o $ ld -lc -I /lib64/ld-linux-x86-64.so.2 he.o 运行: $ ./a.out 段错误 (core dumped) 反汇编: [fe@www Assembly]$ objdump -d a.out a.out: file format elf64-x86-64 Disassembly of section .plt: 0000000000400220 <printf@plt-0x10>: 400220: ff 35 7a 01 20 00 pushq 0x20017a(%rip) # 6003a0 <_GLOBAL_OFFSET_TABLE_+0x8> 400226: ff 25 7c 01 20 00 jmpq *0x20017c(%rip) # 6003a8 <_GLOBAL_OFFSET_TABLE_+0x10> 40022c: 0f 1f 40 00 nopl 0x0(%rax) 0000000000400230 <printf@plt>: 400230: ff 25 7a 01 20 00 jmpq *0x20017a(%rip) # 6003b0 <_GLOBAL_OFFSET_TABLE_+0x18> 400236: 68 00 00 00 00 pushq $0x0 40023b: e9 e0 ff ff ff jmpq 400220 <printf@plt-0x10> Disassembly of section .text: 0000000000400240 <_start>: 400240: 90 nop 400241: 68 b8 03 60 00 pushq $0x6003b8 400246: e8 e5 ff ff ff callq 400230 <printf@plt> 40024b: b8 01 00 00 00 mov $0x1,%eax 400250: bb 00 00 00 00 mov $0x0,%ebx 400255: cd 80 int $0x80
  • 打赏
  • 举报
回复
在System V x64 ABI,RAX指示传入参数使用向量寄存器(对于x64就是MMX/SSEn寄存器)的数量,对于楼主调用printf的例子,没有浮点参数传入,所以就movl $0, %eax了。
fhqdx0012 2014-04-30
  • 打赏
  • 举报
回复
如果没猜错的话 内部应该有类似 rep stos es:[edi] 指令在你那个环境下是啥我不清楚
fhqdx0012 2014-04-30
  • 打赏
  • 举报
回复
你自己看下 printf函数内部 看看eax是不是参数!把反汇编的代码贴上来 没你那个环境不好为你分析
  • 打赏
  • 举报
回复
你可以连接到libc.so试试,用的库是libc.a。
  • 打赏
  • 举报
回复
引用 12 楼 Gfeng168 的回复:
[quote=引用 11 楼 DelphiGuy 的回复:] 64-bit Linux 使用System V ABI,第一个(整数、指针等)参数使用RDI传送,所以你不应该 pushq $output call printf 改成 movq $output, %rdi call printf
我真是无语了啊。。。 Breakpoint 1, _start () at he.s:8 8 nop (gdb) s 9 movq $output, %rdi (gdb) s 10 call printf (gdb) s __printf (format=0x6003c0 "hello world!\n") at printf.c:30 30 { (gdb) s Program received signal SIGSEGV, Segmentation fault. 0x000000350a64f337 in ?? () (gdb) [/quote] 我没有你的运行环境,所以只能推测。 从上述调试来看,调用printf的参数传递都是正常的,问题出在printf内部(printf.c:30行),估计此运行库的printf需要之前的初始化,比如打开标准输出设备之类的,你可以象14楼说的那样写个C程序然后看看汇编输出。
猪头三小队长 2014-04-22
  • 打赏
  • 举报
回复
你直接用c写一段,然后objdump出来看就行了,每种cpu的ABI都不一样,需要你根据具体cpu去做。
unixplus 2014-04-22
  • 打赏
  • 举报
回复
引用 21 楼 DelphiGuy 的回复:
我觉得还是缺少C库初始化代码的问题,C代码在进入main()之前还有startup部分(一般叫做c0xx.asm之类的,如果编译器提供了RTL源码的话)。
那如何初始话C库呢?
  • 打赏
  • 举报
回复
我觉得还是缺少C库初始化代码的问题,C代码在进入main()之前还有startup部分(一般叫做c0xx.asm之类的,如果编译器提供了RTL源码的话)。
加载更多回复(18)

21,497

社区成员

发帖
与我相关
我的任务
社区描述
汇编语言(Assembly Language)是任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。
社区管理员
  • 汇编语言
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧