系统写整数

时间:2013-03-14 20:08:20

标签: assembly formatting x86 memory-address sys

我目前正在开发一个小型ASM程序,它抓取进程ID,然后将其写出屏幕。

以下是代码:

SECTION .bss

    Pid: resb 4

SECTION .text

global start

start:
    mov eax, 0x14       ; System call 20 - Get PID
    push eax            ; Push to stack for BSD
    int 0x80            ; Call
    mov edx, eax        ; Save return value in EDX
    add esp, 0x4        ; Clean up the stack

    push 0x4            ; Push lenth of 4 bytes
    mov [Pid], edx      ; Move address to Pid Buffer
    push Pid
    push 0x1            ; Set file descriptor as 1 (stdout)
    mov eax, 0x4        ; Set system call 4 - Write
    push eax            ; Push the system call to stack
    int 0x80            ; Call
    add esp, 0x10       ; Clean up the stack

    mov eax, 1          ; Set call 1 - sys_exit
    mov ebx, 0          ; All went well
    int 0x80            ; Call

我的问题是程序将PID打印为字符串而不是整数,这里解释的是GDB中显示的具有不同输出格式的相同地址。

String:  0x2016 <Pid>:  "z\035"
Hex:     0x2016 <Pid>:  0x00001d7a
Integer: 0x2016 <Pid>:  7546

系统写调用正在打印字符串,我需要它来打印整数。

有没有一些技巧可以做到这一点,还是我错过了一些明显的东西?

3 个答案:

答案 0 :(得分:2)

您可以将整数转换为字符串,然后打印字符串(使用mov eax,4 ... int 0x80,就像现在一样),或者,您可以printf使用{ {1}},需要call printf(而非global main),global start,并与extern printf进行关联。

关于如何将整数转换为十进制数字(字符串)的示例: How do I print an integer in Assembly Level Programming without printf from the c library?

如何在x86程序集中使用gcc的示例: nasm displaying a dword with printf

请注意,您需要 printf extern printf extern _printf global main,具体取决于您的设置。

答案 1 :(得分:1)

Linux版

以下版本的James Parker代码转换为在 x86 / x86_64 Linux 上运行。

SECTION .data

    LookUpDig db "0123456789"             ; Translation Table
    PIDString db "PID: "
    PIDLength equ $-PIDString

SECTION .bss

    PID: resb 8                           ; Reserve space for result

SECTION .text

            global _start

    _start:
            mov     eax, 0x14             ; GET_PID call
            int     0x80                  ; Call
            mov     ebx, 0xA              ; Set divider to 10
            mov     ebp, PID+6            ; Save the address of PID+6 to EBP
            jnz     LoopMe                ; Run the loop to convert int to string

    LoopMe:
            div     ebx                   ; Divide the PID by 10
            mov     cl, [LookUpDig+edx]   ; Copy ASCII value to CL
            mov     [ebp], cl             ; Copy CL to PID buffer
            dec     ebp                   ; Move to next byte in the buffer
            xor     edx, edx              ; Clear the remainder, else weird results :)
            inc     eax                   ; Increase EAX tricking JNZ
            dec     eax                   ; Decrease to get back to original value
            jnz     LoopMe                ; Loop until EAX is zero (all integers converted)
            jz      PrintOut              ; When done call the print out function

    PrintOut:
            mov     edx, PIDLength        ; Push PIDString Length
            mov     ecx, PIDString        ; Push PIDString
            mov     ebx, 0x1              ; FD stdout
            mov     eax, 0x4              ; sys_write call
            int     0x80                  ; Call kernel

            mov     [PID+7], byte 0xA     ; Push a newline to PID string

            mov     edx, 0x8              ; Max length of 8 bytes
            mov     ecx, PID              ; Push PID value
            mov     ebx, 0x1              ; FD stdout
            mov     eax, 0x4              ; sys_write call
            int     0x80                  ; Call kernel

            mov     eax, 0x1              ; Set system_call
            xor     ebx,ebx               ; Exit_code 0
            int     0x80                  ; Call kernel

<强>构建

nasm -f elf -o prnpid_32.o prnpid_32.asm
ld -o prnpid_32 prnpid_32.o                 # On native 32-bit machine
ld -m elf_i386 -o prnpid_32 prnpid_32.o     # On x86_64

<强>输出:

$ prnpid_32
PID: 1387

答案 2 :(得分:0)

所以我终于找到了问题所在。以下是适合未来需要的人的解决方案。

快速回顾一下,问题是从系统调用GET_PID返回的整数并将其转换为字符串以与SYS_WRITE一起使用。

第一步是取整数并隔离每​​个数字;例如:

Returned PID: 60015 - Grab each integer own its own i.e. 5 1 0 0 6

为了实现这一点,我使用DIV函数将整数除以10,这将剩余部分留在EDX中。如果我们查看数学60015/10会导致6001.5,那么余数5将存储在EDX中。然后可以使用循环来检索每个整数,直到它达到零,然后是JZ以退出循环。

下一步是取每个整数并找到其ASCII码存储到缓冲区中。为此,使用转换表:

LookUpDig db "0123456789"

获取存储在EDX中的数字并将其用作转换表的索引,这将检索该整数的ASCII版本以与sys_write一起使用。

mov cl, [LookUpDig+edx]

取ASCII值并将其插入缓冲区以获得结果。

mov [ebp], cl

将其放入循环中以从返回的整数构建字符串。

完整的程序应该为解决方案提供更多的上下文,我希望这些评论足够详细,可以解释每行代码。

;*************************************************************
; Date    : 02/04/2013                                       *
; Compile : nasm -f macho -o pid.o space.asm                 *
; Link    : ld -macosx_version_min 10.7 -o pid pid.o         *          
; Descr.  : Prints the process PID, could be used in a       *
;           larger program.                                  *
; Nasm v. : NASM version 0.98.40                             *
;*************************************************************

SECTION .data

    LookUpDig db "0123456789"         ; Translation Table
    PIDString db "PID: "
    PIDLength equ $-PIDString

SECTION .bss

    PID: resb 8                       ; Reserve space for result

SECTION .text

global start

start:
    mov eax, 0x14             ; GET_PID call
int 0x80                  ; Call  
mov ebx, 0xA              ; Set divider to 10
mov ebp, PID+6            ; Save the address of PID+6 to EBP
jnz LoopMe                ; Run the loop to convert int to string

LoopMe: 
div ebx                   ; Divide the PID by 10
mov cl, [LookUpDig+edx]   ; Copy ASCII value to CL
mov [ebp], cl             ; Copy CL to PID buffer
dec ebp                   ; Move to next byte in the buffer
xor edx, edx              ; Clear the remainder, leave in for some weird results :)
inc eax                   ; Increase EAX tricking JNZ
dec eax                   ; Decrease to get back to original value
jnz LoopMe                ; Keep looping until EAX is zero (all integers converted)
jz PrintOut               ; When done call the print out function

PrintOut:
push PIDLength            ; Push PIDString Length
push PIDString            ; Push PIDString
push 0x1                  ; FD stdout
mov eax, 0x4              ; sys_write call
push eax                  ; Push call (BSD)
int 0x80                  ; Call
add esp, 0x10             ; Clear up the stack

mov [PID+7], byte 0xA     ; Push a newline to PID string

push 0x8                  ; Max length of 8 bytes
push PID                  ; Push PID value
push 0x1                  ; FD stdout
mov eax, 0x4              ; sys_write call
push eax                  ; Push call (BSD)
int 0x80                  ; Call
add esp, 0x10             ; Clean up stack

mov eax, 0x1              ; Set system_call
push 0x0                  ; Exit_code 0
int 0x80                  ; Call

我希望这有助于将来遇到同样问题的其他人。