« Portfolio

Some simple x86 assembly coding

First experiments with assembly language

Shown below is a typical example program I have made using actual x86 assembly (at&t syntax) with C/C++. Although all such programs remained at this level of complexity, understanding the concepts has been of some help later when debugging programs, and also when making OpenGL vertex and fragment programs.


To form assembly functions easily callable from C or C++, I'd usually use function start and end macros like the ones below. Click the big plus sign (+) to expand the code section.

/*******************************************************************************
* # m_cfunc.inc #
* c function macros
*******************************************************************************/




/*******************************************************************************
* [macros]
*******************************************************************************/

/*******************************************************************************
* cfunc_start                           - start of a c function
*******************************************************************************/
.macro cfunc_start func_name

.globl _\func_name
_\func_name:
    pushl   %ebp
    movl    %esp, %ebp
    
    pushl   %ebx
    pushl   %edi
    pushl   %esi
    push    %ds
    push    %es
    push    %ss

.endm
/******************************************************************************/


/*******************************************************************************
* cfunc_end                             - end of a c function
*******************************************************************************/
.macro cfunc_end

    pop     %ss
    pop     %es
    pop     %ds
    popl    %esi
    popl    %edi
    popl    %ebx
    
    leave
    ret

.endm
/******************************************************************************/

/*******************************************************************************
* [/macros]
*******************************************************************************/




/******************************************************************************/

Then the actual functions get a clear structure. This one checks simple cpu capabilities:

/*******************************************************************************
* [ cpu_feat.s ]
* Cpu feature detection
*******************************************************************************/




/* .include */
.include "m_cfunc.inc"




.text




/*******************************************************************************
* [c functions]
*******************************************************************************/

/*******************************************************************************
* (uint32) cpuFeatures()                - Acquire cpu features
*   (char *)    idStr                       - Cpu id text string
*******************************************************************************/
cfunc_start cpuFeatures

    pushl   8(%ebp)
    movl    $0, %ecx
    pushfl
    popl    %eax
    movl    %eax, %ebx
    xorl    $0x00200000, %eax
    pushl   %eax
    popfl
    pushfl
    popl    %eax
    cmpl    %eax, %ebx
    jz      FEAT_END                    /* No cpuid */
    
    movl    $0, %eax                    /* get cpuid text */
    cpuid
    popl    %eax                        /* get first parameter (char * pointer) to %eax */
    movl    %ebx, (%eax)
    movl    %edx, 4(%eax)
    movl    %ecx, 8(%eax)
    movb    $0x0, 12(%eax)
    
    movl    $1, %ecx                    /* cpuid supported, turn on least significant bit*/
    movl    $0x80000000, %eax
    cpuid
    cmpl    $0x80000000, %eax
    jbe     FEAT_END
    movl    $0x80000001, %eax
    cpuid
    testl   $0x80000000, %edx           /* test bit 31 */
    jz      FEAT_END
    movl    $3, %ecx                    /* 3dNow! supported, turn on second bit too*/
    testl   $0x40000000, %edx           /* test bit 30 */
    jz      FEAT_END
    movl    $7, %ecx                    /* 3dNow!+ supported, turn on third bit too*/
FEAT_END:
    movl    %ecx, %eax

cfunc_end
/******************************************************************************/

/*******************************************************************************
* [/c functions]
*******************************************************************************/




/******************************************************************************/

Corresponding function declaration in a header file:

/******************************************************************************/
// # cpu_feat.h #
// Cpu feature detection
#ifndef __cpu_feat_h__
#define __cpu_feat_h__
/******************************************************************************/


// - #define
#define CPUFEAT_CPUID                   0x1
#define CPUFEAT_3DNOW                   0x2
#define CPUFEAT_3DNOWEX                 0x4
// -


// -- External assembly function definitions
extern "C"
{
    extern unsigned long int cpuFeatures(char *idStr);
}
// --


/******************************************************************************/
#endif
/******************************************************************************/

... and finally just an example call:

#include <stdio.h>
#include <stdlib.h>

#include "cpu_feat.h"

int main()
{
    char idTextStr[13];

    unsigned long int features = cpuFeatures(idTextStr);

    if (features & CPUFEAT_CPUID)
        printf("cpuid, \"%s\"\n", idTextStr);
        
    if (features & CPUFEAT_3DNOW)
        printf("3DNow!\n");
            
    if (features & CPUFEAT_3DNOWEX)
        printf("3DNow!+\n");

    getchar();

    return EXIT_SUCCESS;
}

Mostly the use of assembly was very much like this or with short inline assembly functions, since it was fairly clear that assembly was not any more a feasible option for making larger optimizations.


BTW, for a simple PHP coding example, you can check out the source code of this page below. It also uses jQuery with a custom javascript called expand.js for the code blocks.

asm_esim.php
<?php
$koodinum=1;

function NaytaKoodialue($filename, $islink = true, $hideDefault = false, $dirname = './')
{
    global $koodinum;
    $koodiId = "koodi" . $koodinum . "id";
    echo "<div id=\"" . $koodiId . "\">";
    echo "<div class=\"koodiotsikko\">";
    echo "<a href=\"javascript:toggleDivChild('" . $koodiId . "');\" class=\"expBtn\">&ndash;</a>";
    
    if ($islink)
        echo "<a href=\"" . $dirname . $filename ."\" class=\"koodilinkki\">$filename</a>";
    else
        echo "<span class=\"koodiotsikko\">$filename</span>";
    
    echo "</div>\n<div class=\"koodi\">\n";
    
    $srclines = file($dirname . $filename);
    
    foreach ($srclines as $line)
    {
        // Split with TAB chars, since we convert them to spaces ("&nbsp;")
        // that end at the next char with position == 0 (mod. 4)
        $tabsplit = preg_split('/[\t]/', htmlspecialchars($line));
        
        $j = 0;
        
        $wordcount = count($tabsplit);
        
        // Skip the first tab split word, we process tabs that precede words (possibly empty)
        $j += strlen($tabsplit[0]);
        echo $tabsplit[0];
        
        for ($t = 1; $t < $wordcount; ++$t)
        {
            $word = $tabsplit[$t];
            do
            {
                echo "&nbsp;";
                ++$j;
            } while ($j % 4 != 0);
            $j += strlen($word);
            echo $word;
        }
        
        echo "<br />\n";
    }
    
    echo "</div></div><br />\n";
    
    if ($hideDefault)
        echo "<script type=\"text/javascript\">toggleDivChild('" . $koodiId . "');</script>";
    
    $koodinum++;
}
?>
<!DOCTYPE html>
<html>
<head>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
<title>Portfolio - Some simple x86 assembly coding</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body>

<script src="jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="expand.js"></script>

<div class="ylareuna"></div>

<a class="topbar" href="index.html">&laquo; Portfolio</a>


<div class="keski_container">

    <h1 class="taustaOtsikko">Some simple x86 assembly coding</h1>
    
    <div class="tekstialue">
        
        <h2>First experiments with assembly language</h2>
        
        <p>Shown below is a typical example program I have made using actual x86 assembly
        (at&amp;t syntax) with C/C++. Although all such programs remained at this level of complexity,
        understanding the concepts has been of some help later when debugging programs,
        and also when making OpenGL vertex and fragment programs.
        </p>
        
        <br/>
        
        <p>To form assembly functions easily callable from C or C++,
        I'd usually use function start and end macros like the ones below.
        Click the big plus sign (<b>+</b>) to expand the code section.
        </p>
        
        <?php
            NaytaKoodialue("m_cfunc.inc", true, true, "asm_esim/");
        ?>
        
        <p>Then the actual functions get a clear structure.
        This one checks simple cpu capabilities:
        </p>
        
        <?php
            NaytaKoodialue("cpu_feat.s", true, true, "asm_esim/");
        ?>
        
        <p>Corresponding function declaration in a header file:</p>
        
        <?php
            NaytaKoodialue("cpu_feat.h", true, true, "asm_esim/");
        ?>
        
        <p>... and finally just an example call:</p>
        
        <?php
            NaytaKoodialue("main.cc", true, true, "asm_esim/");
        ?>
        
        
        <p>Mostly the use of assembly was very much like this or with short inline
        assembly functions, since it was fairly clear that assembly was not any more
        a feasible option for making larger optimizations.
        </p>
        
        <br/>
        
        
        <p>BTW, for a simple <span class="emph">PHP</span> coding example, you can check out the
        source code of this page below. It also uses <span class="emph">jQuery</span> with a custom javascript called
        <a href="expand.js">expand.js</a> for the code blocks.</p>
        
        <?php
            NaytaKoodialue("asm_esim.php", false, true);
        ?>
        
        <br/>
        
        <div class="alareuna"></div>
    </div>

</div>


</body>
</html>