flat assembler
Message board for the users of flat assembler.

Index > Linux > 64-bit libc syntax

Author
Thread Post new topic Reply to topic
donn



Joined: 05 Mar 2010
Posts: 300
donn 31 May 2010, 21:49
Hi I have an app written by Jeff Duntemann, which was meant for 32-bit nasm, and wanted to use it with fasm 64-bit. It demonstrates how to use libc. Assemble first, then link with gcc. Wasn't sure how to reserve 128 bytes named InString, so tried 'InString db 0,128' but know that's probably wrong. Wrote extrn '_stdin' as stdin and neither that nor 'extrn 'stdin' as _stdin' worked. I've seen both ways in examples and in documentation but it says illegal instruction. That seems funny, dont know whats wrong. Here's the start of the code:

Code:
SPrompt  db 'Enter string data, followed by Enter: ',0           

IPrompt  db 'Enter an integer value, followed by Enter:     ',0

IFormat  db '%d',0

SShow    db 'The string you entered was: %s',10,0

IShow    db 'The integer value you entered was: %5d',10,0





IntVal   dd 0    ; Reserve an uninitialized double word

InString db 0,128 ; Reserve 128 bytes for string entry buffer

     

extrn '_stdin' as stdin               ; Standard file variable for input

extrn '_fgets' as fgets

extrn '_printf' as printf  

extrn '_scanf' as scanf               

global main             ; Required so linker can find entry point    


Wondering if anyone knows about this,
Denat[/code]
Post 31 May 2010, 21:49
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 19488
Location: In your JS exploiting you and your system
revolution 31 May 2010, 22:57
denat: You have to state the format in the source before you put any instructions or code.
Code:
format elf    
To reserve memory use this:
Code:
rb 128 ;reserve 128 bytes    
It is all described in the manual.
Post 31 May 2010, 22:57
View user's profile Send private message Visit poster's website Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4624
Location: Argentina
LocoDelAssembly 31 May 2010, 23:21
There are more errors actually (for instance "global" should be "public"). It is worth noting that fasm is not just a nasm clone written in Assembly instead of C, it is true that them share some things in common at the syntax level, but them are not 100% compatible with each other.

I found the author's site and example so I'm giving here the 64-bit version with fasm:
Code:
; This is a modification of Jeff Duntemann example to work in 64-bit and be compilable with fasm
;  Build using these commands:
;    fasm charsin.asm
;    gcc charsin.o -o charsin


;=== Comment from Original author follows:
;  Source name     : CHARSIN.ASM
;  Executable name : CHARSIN
;  Version         : 2.0
;  Created date    : 11/21/1999
;  Last update     : 5/28/2009
;  Author          : Jeff Duntemann
;  Description     : A character input demo for Linux, using NASM 2.05,
;       incorporating calls to both fgets() and scanf().
;
;  Build using these commands:
;    nasm -f elf -g -F stabs charsin.asm
;    gcc charsin.o -o charsin
;       

format elf64
section '.data'  ;[SECTION .data]                 ; Section containing initialised data
     
SPrompt  db 'Enter string data, followed by Enter: ',0                
IPrompt  db 'Enter an integer value, followed by Enter:  ',0
IFormat  db '%d',0
SShow  db 'The string you entered was: %s',10,0
IShow         db 'The integer value you entered was: %5d',10,0
     
section '.bss' writable ;[SECTION .bss]          ; Section containing uninitialized data

IntVal     rd 1 ;resd   1       ; Reserve an uninitialized double word
InString rb 128 ;resb 128       ; Reserve 128 bytes for string entry buffer
         
section '.text' executable ;[SECTION .text]         ; Section containing code

extrn stdin ;extern stdin            ; Standard file variable for input
extrn fgets ;extern fgets
extrn printf ;extern printf
extrn scanf ;extern scanf
public main ;global main             ; Required so linker can find entry point
       
main:
       push rbp ;ebp        ; Set up stack frame for debugger
      mov rbp, rsp ;ebp,esp
       ; === The saving was innecesary as them are not written (and in 64-bit you have to preserve a different set anyway)
 ;push ebx        ; Program must preserve ebp, ebx, esi, & edi
   ;push esi
   ;push edi
;;; Everything before this is boilerplate; use it for all ordinary apps!

; First, an example of safely limited string input using fgets:
    mov rdi, SPrompt ;push SPrompt    ; Push address of the prompt string
        xor eax, eax ;[added instruction] AL specifies the number of vector registers used for variadic functions. (Got segfault without this)
     call printf     ; Display it
        ;add esp,4       ; Stack cleanup for 1 parm
 
    mov rdx, [stdin] ;push dword [stdin]  ; Push file handle for standard input
 mov esi, 72 ;push 72         ; Accept no more than 72 chars from keybd ;;; (NOTE: The instruction automatically clears RSI[63:32])
  mov rdi, InString ;push InString   ; Push address of buffer for entered chars
       call fgets      ; Call fgets
        ;add esp,12      ; Stack cleanup: 3 parms X 4 bytes = 12

    mov rsi, InString ;push InString   ; Push address of entered string data buffer
     mov rdi, SShow ;push SShow      ; Push address of the string display prompt
        xor eax, eax ;[added instruction] AL specifies the number of vector registers used for variadic functions. (Got segfault without this)
       call printf     ; Display it
        ;add esp,8       ; Stack cleanup: 2 parms X 4 bytes = 8

; Next, use scanf() to enter numeric data:
   mov rdi, IPrompt ;push IPrompt    ; Push address of the integer input prompt
        xor eax, eax;[added instruction] AL specifies the number of vector registers used for variadic functions. (Got segfault without this)
       call printf     ; Display it
        ;add esp,4       ; Stack cleanup for 1 parm

;Code that was used to check Ubuntu behavior
;xor eax, eax
;mov qword [IntVal], rax

    mov rsi, IntVal ;push IntVal     ; Push the address of the integer buffer
   mov rdi, IFormat ;push IFormat    ; Push the address of the integer format string
        xor eax, eax;[added instruction] AL specifies the number of vector registers used for variadic functions. (Got segfault without this)
  call scanf      ; Call scanf to enter numeric data ; (NOTE: At least in Ubuntu 9.10, scanf is reading the number as a "long long" and then returning the lower half)
  ;add esp,8       ; Stack cleanup: 2 parms X 4 bytes = 8

;Code that was used to check Ubuntu behavior
;cmp dword [IntVal+4], 0
;je @f
;int3
;@@:
  mov esi, [IntVal] ;push dword [IntVal]     ; Push integer value to display
  mov rdi, IShow ;push IShow      ; Push base string
        xor eax, eax;[added instruction] AL specifies the number of vector registers used for variadic functions. (Got segfault without this)
 call printf     ; Call printf to convert & display the integer
  ;add esp,8       ; Stack cleanup: 2 parms X 4 bytes = 8
 
;;; Everything after this is boilerplate; use it for all ordinary apps!
 ;=== Were not saved (see prolog comment)
    ;pop edi         ; Restore saved registers
  ;pop esi
    ;pop ebx
    mov rsp, rbp ;esp,ebp     ; Destroy stack frame before returning
    pop rbp ;ebp
        ret             ; Return control to Linux

; === The original author seems to have repeated the data and bss sections using uncapitalized names.
; === I'll proceed commenting the remaining of the code for being not useful

;[SECTION .data]         ; Section containing initialised data
;
;sprompt  db 'Enter string data, followed by Enter: ',0
;iprompt  db 'Enter an integer value, followed by Enter:  ',0
;iformat  db '%d',0
;sshow    db 'The string you entered was: %s',10,0
;ishow    db 'The integer value you entered was: %5d',10,0
;
;[SECTION .bss]          ; Section containing uninitialized data
;
;intval   resd   1       ; Reserve an uninitialized double word
;instring resb 128       ; Reserve 128 bytes for string entry buffer    
Code:
loco@athlon64:~$ fasm charsin.asm 
flat assembler  version 1.69.11  (16384 kilobytes memory)
1 passes, 1487 bytes.
loco@athlon64:~$ gcc charsin.o -o charsin
loco@athlon64:~$ ./charsin
Enter string data, followed by Enter: Hello World! :D
The string you entered was: Hello World! :D

Enter an integer value, followed by Enter:  31052010
The integer value you entered was: 31052010
loco@athlon64:~$    


Underscore decoration was not needed, however, I'm not sure if that is always the case or if it is my libs that are exporting the functions twice to make them reachable in both ways.
Post 31 May 2010, 23:21
View user's profile Send private message Reply with quote
donn



Joined: 05 Mar 2010
Posts: 300
donn 01 Jun 2010, 03:31
So awesome, you helped with this step 100%. Read through the 64-version example, things like the xor eax, eax I probably wouldn't have been able to come up with, with even the segfault error displaying. I'm going to put the knowledge you both gave me to good use, keep figuring things out, and getting the basis down more. The example ran beautifully, cool, great that you know these things.

That was very helpful, and very fast too,
Denat
Post 01 Jun 2010, 03:31
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4624
Location: Argentina
LocoDelAssembly 01 Jun 2010, 05:06
For more information about the calling convention see this doc (I've to read it myself when porting Jeff's code): http://www.x86-64.org/documentation/abi.pdf

Note that only AL needs to be set to zero, but I thought that clearing the entire RAX register (xor eax, eax also clears RAX[63:32]) may be handled by the processor more easily (the size of "mov al, 0" is the same that the size of "xor eax, eax", two).
Post 01 Jun 2010, 05:06
View user's profile Send private message Reply with quote
donn



Joined: 05 Mar 2010
Posts: 300
donn 06 Jun 2010, 23:42
Hey, seems page 21 is very helpful, shows the register behaviors in a table. With rbx, rsp, rbp and r12-r15 being saved and keeping their values once the global function is called. But rbp can be used for the stack frame by pushing it, Why is rsp said to be preserved if it is updated once the stack decreases, maybe because the function doesn't interfere with its role with things we don't need? It also shows the argument order registers, rdi rsi rdx, very cool. It seems xmm0-xmm1 can return floating point, where xmm2-xmm7 pass only (after xmm0-xmm1 are used), but is page 23 saying otherwise? it goes xmm0, then 1, then ymm2 then xmm3, skipping xmm2 also. This can probably be tested. I think it says for AVX like usage, ymm and xmm are interchangeable, they can have the same value, only one can be used at a time. That makes sense, then. Solid, LocoDelAssembly, good night.

Denat
Post 06 Jun 2010, 23:42
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2023, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.

Website powered by rwasa.