NASM - The Netwide Assembler

NASM Forum => Example Code => Topic started by: TightCoderEx on June 13, 2012, 12:01:17 PM

Title: TERMIOS Improved
Post by: TightCoderEx on June 13, 2012, 12:01:17 PM
After much experimentation and even though GDB really doesn't like this, I've settled on STDCALL, probably from having done it that way so long, it just seems easier to design algos

This is primarily designed to facilitate non-canonical input in my apps, but additional functionality can be incorporated using mode SET = 1 and modifying whatever flags outside the procedure.

Code: [Select]
        SYS_IOCTL       equ         16
                    TCGETS      equ     0x5401
                    TCSETS      equ     0x5402

ARG1 equ 16
ARG2 equ 24

global Termios
extern FmtErr

      section .text
; =============================================================================================
; bool Termios ( int Function, char *Termios_struct )

; ENTER: ARG1 = Function # 0 = GET, 1 = SET, 2 = TOGGLE
; ARG2 = Pointer to termios structure

; LEAVE: RAX = True (-1), function failed, otherwise False (0).
; ---------------------------------------------------------------------------------------------

  Termios: push rbp
  mov rbp, rsp ; So ARG1 can be addressed conventionally
  push rdx
  push rsi ; Preserve
  push rdi
  ; RDX & RDI are common to all modes
  xor rdi, rdi ; File descriptor ( can be STDIN or STDOUT )
  mov rdx, [rbp + ARG2] ; Pointer termios structure
  ; Get function mode from caller and because setting is more probably we'll set it
  ; as default
  mov rcx, [rbp + ARG1] ; Get function mode
  mov rax, rcx ; Simple way of resetting RAX
  mov ax, TCGETS ; Most probable = 5402H
  cmp cl, 1
  jb .DoFunc
; Toggle bits 1 and 0 of AL.  Hopefully kernel never changes this number

  .Set xor al, 3 ; Now = 5401H
  cmp cl, 1 ; Are we just setting new functionality
  jz .DoFunc
  ; Caller could have done this, but this method save a bit of code overall because
  ; it might be called multiple times in app.
  xor byte [rdx + 12], MASK ; Toggle NON-CANONICAL on/off

  ; Finish setting up registers.
      .DoFunc mov rsi, rax ; Move function into RSI
  mov ax, SYS_IOCTL
  syscall ; Execute function
  or rax, rax
  jge .Exit
  push 0 ; Have proc find syscall address
  push rax ; Unmodifed error code
  call FmtErr ; Display error
  or rax, -1 ; Set error condition
  .Exit pop rdi
  pop rsi ; Retrieve
  pop rdx
  leave ; Kill frame
  ret 16 ; Waste 2 arguments
Title: Re: TERMIOS Improved
Post by: Rob Neff on June 13, 2012, 01:41:39 PM
Technically, for STDCALL calling convention, shouldn't the method signature be Termios@12
Microsoft ( who designed that convention )  doesn't use it for native x64 apps. I'm just nit-picking ;D
Title: Re: TERMIOS Improved
Post by: TightCoderEx on June 13, 2012, 04:00:12 PM
I had noticed too by default not even gcc uses STDCALL.  I'm not sure the reason, but I do know if a programmer or some kind of change in kernel resets the "D" flag, my apps will be hooped.  In MASM, this call would have been decorated _Termios@16. It seems ld requires no such decoration, not even in an archive.

Title: Re: TERMIOS Improved
Post by: Rob Neff on June 13, 2012, 09:09:02 PM
Oh yeah, I forgot about that pesky prefix!

Also, are you certain about how MASM decorates your function?  I haven't played with MASM since my DOS days.
Given that your method is defined as bool Termios ( int Function, char *Termios_struct )
the signature for Win32 would definitely be _Termios@8 but I would think only the pointer would expand on x64, thus my original _Termios@12.  To my knowledge there is no x64 STDCALL so I'm curious as to MASM decorating it as _Termios@16.
Title: Re: TERMIOS Improved
Post by: TightCoderEx on June 13, 2012, 10:39:10 PM
This is what I use for a test bench. The comment section denotes stack addresses with 0x7ffffffe stripped from them.

Code: [Select]
   0: c8 30 00 00          enter  0x30,0x0 ; 0x250
   4: 54                    push   rsp ; 0x218
   5: 6a 00                push   0x0 ; 0x210
   7: e8 00 00 00 00        call   Termios ; 0x208

NASM complains about pushing a 32 bit register, similarly it doesn't like greater than a 32 bit immediate.  I assume the same thing would happen using MASM on W7, which would mean _Termios@16 be the result.  Maybe somebody will drop by that uses 64 bit MASM and give us some insight as to what actually happens.
Title: Re: TERMIOS Improved
Post by: Bryant Keller on June 13, 2012, 11:06:36 PM
I had noticed too by default not even gcc uses STDCALL.

Code: (gcc compatible) [Select]
#define STDCALL __attribute__((stdcall))
bool STDCALL Termios ( int Function, char *Termios_struct );
Title: Re: TERMIOS Improved
Post by: Rob Neff on June 14, 2012, 03:36:47 PM
Thinking a little more about it: x64 stack alignment requirements may be the reason for _Termios@16 in MASM.
At this point I'm bailing out and letting someone else with MASM experience chime in.  ;D
Title: Re: TERMIOS Improved
Post by: Keith Kanios on June 14, 2012, 06:12:41 PM
Compliance with the calling conventions and instruction set is key to understanding the decisions MASM makes.

On x86-64, push/pop is 64-bit. 32-bit immediate values are sign-extended to 64-bit. At the opcode level, push ax, push eax and push rax are all the same (although pushing r8 through r15 involves a prefix) and the current processor mode (16/32/64) dictates the actual data size. It is up to the assembler to figure out if you are doing something "illegal" on a logical level, e.g. pushing a 32-bit register within code meant for 64-bit mode. I am not sure if MASM specifically will indicate such as an illegal operation, or quietly let it pass.

Also, SSE being part of the x86-64 architecture is probably one good reason to standardize around having 16-byte aligned stacks. The x86-64 calling convention found at the first link, below, enforces exactly that -- but don't confuse that (used by almost everything major *but* Windows) with Microsoft's x64 calling convention.

Useful Links: