Be Driven
  Device Drivers in the Be Os
     
    Using Assembler in C

Assembler Foreword

I am not an expert in this field.
In short, If ANYBODY has more information/real world experience, please Email me!

Intermixing Assembler and C in Device Drivers

Inserting straight forward assembler in C relatively painless, and can be usefull at times, when you find something is amiss in the compiled code (especially in a tight loop).

So when you want to insert some Assembler inside your C code, then the following "asm { };" will work fine on a PPC compiler, but on an intel you have to use "#pragma asm /* your command here*/ "..

ANYBODY, INTEL MUST HAVE A BETTER WAY TO DO THIS??????

As you can imagine, anything found inside this is processor dependent to the max, and should always be wrapped around #ifdefs..

#ifdef __INTEL__
    #pragma asm mov ax, 0
    #pragma asm mov bx, 0
    // There has to be a better way to do this????????????
#elifdef __POWERPC__ asm{ /* Some nice PPC code */ } #else // C style equivilent or warning.. #endif

Currently the only #defs for Processors in R4.0 are as follows :
__INTEL__, __POWERPC__, __SH__
// That is 2 _ _underscores_ _

Given you might also want to include multiple versions of assembler depending on the processor (Like MMX extensions, or PIII optimizations or what have you), you can call get_system_info(&sys_info); to get processor details from your driver for this purpose.

You should check <OS.h> towards the bottom of the file for an interesting list of Processors and processor types, and the Max Cpu count currently enabled for your build! Dying for a B_CPU_Z80 build ;-)

Custom Assembler Instructions

As always, a compiler may not be nice enough to incorporate all the newest assembler instructions that just happen to exist on your particular processor.
below is an example of how to get around it taken directly from Dmitriy's code.. ( If your looking to do anything really tricky on an intel, be sure to read his source code, you sure to find something interesting... )

Please note, that that this was compiled under V3.0, using the metrowerks compiler... Differences exist in the GNU compiler.. I have commented in a version that works on V4.0, using gcc.. <YUCK>

Windows 95 Experience on BeOS -- Or How to Hack on BeOS,
Be Newsletter, Volume II, Issue 21.
By Dmitriy Budko
"

/* 
Metrowerks inline assembler does not support 
Move to/from x86 registers so assemble them manually. 
*/ 
uint8 mov_cr0_eax__ret[] = 
{ 
    0x0F, 0x22, 0xC0, /* mov cr0, eax */ 
    0xC3 /* ret */ 
};
static void set_cr0(uint32 val) { /* Generate the correct relocation record for code in the data segment. Simple "call mov_cr0_eax__ret" will be patched as if mov_cr0_eax__ret were in the code segment. */ void* f_ptr = mov_cr0_eax__ret; asm { mov eax, val call f_ptr // [ Ben Modified example of how to call now under gcc ] // #pragma asm mov eax, val // #pragma asm call f_ptr } }

"Another Example is as follows from :
Outsmarting the Scheduler
Be Newsletter Volume II, Issue 27
By Ficus Kirkpatrick
"

/* globally declared */ 
static uchar *hack_area; 


static uchar springboard[] = 
    "\xb8\x00\x00\x00\x00" /* mov eax, ... */ 
    "\x50" /* push eax */ 
    "\xe8\x00\x00\x00\x00" /* call ... */ 

    "\x58" /* pop eax */ 
    "\xb8\x01\x00\x00\x00" /* mov eax, 1 */ 
    "\xc3"; /* ret */ 
    
/* in wakeup_open() */ 
    if ((aid = find_area("wakeup hack")) < 0) { 
        /* if the area doesn't exist, create it */ 
        create_area("wakeup hack", &hack_area, 
                    B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, 
                    B_FULL_LOCK, B_READ_AREA|B_WRITE_AREA);
    } else { 
        /* otherwise just reuse it -- we are only single-open */ 
        get_area_info(aid, &ai); 
        hack_area = (uchar *)ai.address; 
    } 
    /* copy the springboard code into the area */ 
    memcpy(hack_area, springboard, sizeof(springboard)); 
    
    /* patch the springboard code to have the relocated address 
    * of release_sem, as well as the correct sem_id to pass to it 
    */ 
    *(sem_id *)(hack_area + 1) = wakeup_sem; 
    *(uint32 *)(hack_area + 7) = 
            ((uint32)release_sem - (uint32)hack_area - 11); 

"I believe there is also another trick, that I have used on other compilers that also works on GCC for Intel.

Generating Assembler from C Code

It would seem that Ben Gittins (iiisexrex@yahoo.com) said:
> Are there any other ways of doing inline assembler in the C.

try http://www.calderasystems.com/LDP/HOWTO/Assembly-HOWTO-3.html
for an overview of the possible tools.

and for inline asm with gcc (probably what you want) try:
http://www.rt.e-technik.tu-darmstadt.de/~georg/djgpp/djgpp_asm.html

this is the basic format for gcc inline asm:

asm("statements" : output_registers : input_registers : clobbered_registers);

this example reads the value of the tsc register on a p5+ machine, the tsc
is a 64 bit free running counter (at the core frequency). it basicly says
call the rdtsc instruction (which puts it's values in eax and edx) then
store eax in "low" and edx in "high":

static inline unsigned long long read_tsc(void) 
{ 
unsigned long low, high; 


    __asm__ ("rdtsc" 
            : "=a" (low), "=d" (high) 
            : 
            : "eax", "edx"); 
    return (((unsigned long long) high << 32) | low); 
}


cheers, Angus.

------------------------------------------
>Using the gcc compiler on my intel box, the only way I can seem to do any
>assember in C, is to use the
>
>#pragma asm mov ax, 0
>
>style. Now this quickly becomes ugly!!
>
>Are there any other ways of doing inline assembler in the C.

Yep. You need to use the gas (GNU assembler) syntax, which is (as most
other open-source stuff) extremely powerful and extremely painful to use.

I don't know the gas syntax at all.

If you need more than two or three instructions, I would personnally
recommend NASM, which is free (but not GPL, so that it cannot be on
the BeOS CD) and works rather well in most cases (don't try to
use the macros, though. Forget about 3DNow! and KNI).

>Also, looking at the output provided by Dissasembling an object is, quite
>simply, EEK!!! it doesn't even output the assembler in human readable form..
>(only in binary).

objdump --disassemble will give you a human-readable form.

>Also, it doesn't output the C code in parrallel to the source as comments..

That would have to be in a debugger. unfortunately bdb is only a source-level
debugger, not an assembly-level.

-- Jean-Baptiste Queru - BedevID #E-1145


The Communal Be Documentation Site
1999 - bedriven.miffy.org