2013-03-14 74 views
0

我目前正在研究一個小的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 

系統寫入調用打印字符串,我需要它打印整數。

有沒有一些技巧可以做到這一點,或者我錯過了明顯的東西?

+0

哪個數字系統(二進制,十進制,十六進制),要使用? – nrz 2013-03-14 20:30:35

+0

我希望它返回一個無符號整數。 – 2013-03-14 20:36:12

+0

操作系統的返回值?那麼這根本就不在於印刷。在這種情況下,'mov eax,1','mov ebx,my_value','int 0x80'。或者你的意思是打印一個十進制無符號整數? – nrz 2013-03-14 20:38:40

回答

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 "" 

以存儲在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 ""   ; 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 

我希望這有助於任何人在未來有同樣的問題。

2

您可以您的整數轉換成字符串,然後打印字符串(與mov eax,4 ... int 0x80,因爲你現在做的),或者,你可以使用printfcall printf,這需要(而不是global startglobal mainextern printf ,並與gcc做鏈接。

如何整數轉換成十進制數(串)的一個例子: How do I print an integer in Assembly Level Programming without printf from the c library?

如何在x86彙編使用printf一個例子: nasm displaying a dword with printf

請注意,你需要要麼extern printfextern _printf,和要麼global mainglobal _main,具體取決於您的設置。

+0

這是一個好主意,我會嘗試先將整數轉換爲字符串。謝謝,讓我們看看這是怎麼回事:) – 2013-03-14 20:37:12

+0

我似乎無法得到任何進一步的,我試圖轉換爲一個字符串,但我不能訪問小數點來做到這一點。另外我想避免調用C函數,我試圖保持純粹的彙編。 – 2013-03-14 21:25:12

0

Linux版本

這裏是詹姆斯·帕克的代碼版本轉換爲上的x86/x86_64的Linux的運行。

SECTION .data 

    LookUpDig db ""    ; 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