在printf上的linux上的分段故障ASM

时间:2014-01-24 23:43:01

标签: linux assembly 64-bit yasm

以下是一本书中的程序(Seyfarth的64位英特尔汇编语言程序设计简介,2012),第9章。故障(在gdb中)是:

  

编程接收信号SIGSEGV,分段故障。   __printf_size中的0x00007ffff7aa10a5(fp = 0x400400,info = 0x0,      args =)at printf_size.c:199   199 printf_size.c:没有这样的文件或目录。

在本章之前,我成功地使用了以下内容来“按照建议生成目标文件”

yasm -f elf64 -g dwarf2 -l exit.lst exit.asm

然后,

ld -o prgm prgm.o

这是从书中复制的程序(l 10 push rbp;我先是先重新编写;但结果相同):

    segment .text
    global  main
    extern  printf

;   void print_max  ( long a, long b )
;   {
a   equ 0
b   equ 8
print_max:
    push    rbp;     ;normal stack frame
    mov     rbp, rsp
;   leave space for a, b and max
    sub     rsp, 32
;   int max;
    max equ 16
    mov [rsp+a], rdi ; save a
    mov [rsp+b], rsi ; save b
;   max = a;
    mov [rsp+max], rdi
;   if ( b > max ) max = b;
    cmp rsi, rdi
    jng skip
    mov [rsp+max], rsi
skip:
    ;   printf ( "max(%1d,%1d ) = %1d\n",
    ;                a, b, max );
    segment .data
fmt db  'max(%1d,%1d) = %1d',0xa,0
    segment .text
    lea rdi, [fmt]
    mov rsi, [rsp+a]
    mov rdx, [rsp+b]
    mov rcx, [rsp+max]
    call printf
 ; }
    leave
    ret

main:
    push    rbp
    mov     rbp, rsp
;   print_max ( 100, 200 );
    mov     rdi, 100    ;first parameter
    mov     rsi, 200    ;second parameter
    call    print_max
    xor     eax, eax    ;to return 0
    leave
    ret

在本章(“Hello World”示例)中与先前程序类似的分段错误之后,我使用了

gcc -o prgm prgm.o

直到这个计划才开始工作。

2 个答案:

答案 0 :(得分:1)

如果你要使用C库中的函数,使用gcc链接是最简单的方法,因为gcc会在“幕后”为你处理一些事情。

要仅使用ld,您需要链接到ld-linux-x86-64.so.2并将其传递给-lc以链接到C库。

接下来,您使用的是printf错误。如果你没有使用浮点寄存器(你不是),你需要“归零”rax

此外,由于您要链接到C库,因此ret不能main,而是致电exit

lea     rdi, [fmt]
mov     rsi, [rsp+a]
mov     rdx, [rsp+b]
mov     rcx, [rsp+max]
xor     rax, rax                      ; # of floating point registers used.
call    printf

;   print_max ( 100, 200 );
mov     rdi, 100    ;first parameter
mov     rsi, 200    ;second parameter
call    print_max
xor     eax, eax    ;to return 0
leave

xor     rdi, rdi
call    exit
  

ld -o $(APP)$(APP).o -lc -I / lib64 / ld-linux-x86-64.so.2

和输出:

max(100,200)= 200

答案 1 :(得分:0)

枪手给出了一个很好的总结。该程序应该在rax中放置0。这可以使用" xor eax,eax"这是在x86-64模式下将寄存器归零的常用方法。寄存器的上半部分用xor和32位寄存器清零,下半部分取决于使用的2个寄存器的位(使用eax,eax结果为0)。