LinuxQuestions.org
Review your favorite Linux distribution.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Blogs > rainbowsally
User Name
Password

Notices


Rate this Entry

Assembler Stuff: Asm and Inline Asm

Posted 01-25-2012 at 07:15 PM by rainbowsally

Assembler Stuff: Asm and Inline Asm

Features:
  • Asm and inline asm examples
  • Using C macros to create global function names
  • Intel and ATT syntax
  • Viewing disassembly in a *.s file and using objdump

Let's get right to the point...

Code:
// main.c
// COMPILE: gcc main.c -o main --save-temps
// take a look at the C asm output file, 'main.s' afterwar

// 64 bit asm keeps part of the stack in registers in C, so let's
// keep this simple and compilt it for 32 bit intel x86.

#include <stdio.h>

// We can use C macros to hide ugly details such as giving 
// the function a global name we can use to call it.  We'll
// use backslashes to span lines to make it more readable.

#define LABEL(name) \
    ".text;\n" \
    ".globl "#name";\n" \
    ".type " #name", @function;\n" \
    ""#name":"

#define FUNCTION(name) \
    asm( \
    ".text;\n" \
    ".align 4\n" \
    LABEL(name) \
    );

// returns char* as a long
long test_readvar(char* s);

// sets [addr] = s
void test_writevar(char** addr, const char* s);

// functionally identical to this
void c_writevar(char** addr, char* s)
{
  *addr = s;
}

char* watch; // copy a value here to see it in a debugger

// Let's create a stretch of throwaway code in C in which we 
// can compile some straight assembler routines.  This basically
// switches the assembler to compile in the .text section.

void code_section()
{
  // We are now in a code block created by C, i.e., the .text
  // section, so the following FUNCTION will be somewhat redundant
  // but certainly easier to read than the gory details of the full
  // declaration.
  
  // C pushes the params on the stack, right to left.  This is 
  // straight asm code so there is no frame pointer, esp points
  // to the return address, esp+4 points to first param in param
  // list.
  FUNCTION(test_readvar) // return contents of value on the stack
  asm(
      // This is the first opcode that executes in the call.
      "mov 4(%esp), %eax;"
      
      // Note that we don't need newlines after the semicolons
      // here, but if you have a syntax error there will be 
      // few usable clues about where it occurred.
      
      // And this is the last byte to execute in this code.
      "ret;"
  );
  // end function
  // Now let's try  intel syntax
  FUNCTION(test_writevar) // (var, val)
  asm(
      ".intel_syntax noprefix;\n"
      
      // C let's us play with eax and edx, but others need to be 
      // saved and restored.
      "MOV    EAX, DWORD PTR [ESP+4];\n"  // var
      "MOV    EDX, DWORD PTR [ESP+8];\n"  // val
      "MOV    DWORD PTR [EAX], EDX;\n"    // [var] = val
      "RET;\n"
      
      // if we don't switch back, C will choke on intel syntax
      ".att_syntax\n"
     );
}

void thats_all_folks() {printf("That's All Folks!\n\n");}

int main()
{
  char*x = "testing";
  // first test
  long addr = test_readvar(x);
  printf("readvar -> Addr: 0x%X\tValue: %s\n", addr, x);
  
  // second test, and also rerun first routine for printout
  test_writevar(&x, "finished");
  
  addr = test_readvar(x); // to get new value
  printf("readvar -> Addr: 0x%X\tValue: %s\n", addr, x);
  
  // and we can inline asm with C as well
  asm( "call thats_all_folks;");
  return 0;
}
Also, here's the gcc equivalent for the stdcall call types if you want it. Normally, in C, the caller cleans up the stack, though. Tends to be
faster.

Pick the one you're most familiar with; __stdcall, _stdcall, or stdcall
Code:
#define __stdcall __attribute__((__stdcall__))
#define _stdcall __attribute__((__stdcall__))
#define stdcall __attribute__((__stdcall__))
You only need those for the prototype declarations. Asm is asm.

To see the intel syntax disassembly (dest, src) type:
Code:
objdump -d main -M intel_syntax
or remove the "-M ..." part for ATT (src, dest) disassembly.

Try the compile with adding the flag '--omit-frame-pointer' and look at the c_writevar code compared to test_writevar in objdump.

Code:
tofile objdump -d -M intel_syntax main
[If you don't have 'tofile', you can pipe it through 'more' or whatever...]

Here's what I get...
Code:
08048454 <c_writevar>:
 8048454: 8b 44 24 04           mov    eax,DWORD PTR [esp+0x4]
 8048458: 8b 54 24 08           mov    edx,DWORD PTR [esp+0x8]
 804845c: 89 10                 mov    DWORD PTR [eax],edx
 804845e: c3                    ret    

08048468 <test_writevar>:
 8048468: 8b 44 24 04           mov    eax,DWORD PTR [esp+0x4]
 804846c: 8b 54 24 08           mov    edx,DWORD PTR [esp+0x8]
 8048470: 89 10                 mov    DWORD PTR [eax],edx
 8048472: c3                    ret
:-)
Posted in Uncategorized
Views 1302 Comments 0
« Prev     Main     Next »
Total Comments 0

Comments

 

  



All times are GMT -5. The time now is 11:26 AM.

Main Menu
Advertisement
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration