Inline ASM in C, compiled with MinGW/GCC using "-masm=intel": "undefined reference"

econsteve picture econsteve · Mar 15, 2013 · Viewed 9k times · Source

I've been looking around a lot for examples of using inline ASM and I've seen seen a few different approaches.

I've gone with the -masm=intel option when compiling. As I understand it, when using this option you can just write the inline ASM as you would with intel syntax.

I have also seen approaches where people use ".intel_syntax"

When I compile I get the following message.

    i586-mingw32msvc-gcc -masm=intel -o KDOS.exe KDOS.c
    /tmp/ccVIXhRF.o:KDOS.c:(.text+0x5f): undefined reference to `address'
    /tmp/ccVIXhRF.o:KDOS.c:(.text+0x6a): undefined reference to `ipAddr'
    /tmp/ccVIXhRF.o:KDOS.c:(.text+0x79): undefined reference to `csAddr'
    /tmp/ccVIXhRF.o:KDOS.c:(.text+0x11d): undefined reference to `address'
    collect2: ld returned 1 exit status

I've looked around for a solution but I can't seem to find one. I've seen threads saying you can't pass C variables into inline ASM, but I've also seen some stuff saying there are workarounds. They didn't quite apply to what I was doing though so I wasn't really sure what to make of them. Sorry if it is an obvious answer but this is my first time using inline ASM much less fooling around with converting the syntax.

Here is my code. I am working through a book and this is some sample code within it. It was not compiled with gcc in the book so this is why I need to convert to intel syntax, because I need it to run on windows obviously. This is my modified version of the code:

// KDOS.c
// Chapter 2

#include<stdio.h>

#define WORD unsigned short

#define IDT_001_ADDR    0        //start address of first IVT vector
#define IDT_255_ADDR    1020     //start address of last IVT vector
#define IDT_VECTOR_SZ   4        //size of each IVT Vector (in bytes)

#define BP    __asm{ int 0x3 }    //break point

void main()
{
    WORD csAddr;                 //Code segment of given interrupt
    WORD ipAddr;                 //Starting IP for given interrupt
    short address;               //address in memory (0-1020)
    WORD vector;                 //IVT entry ID (i.e., 0..255)
    char dummy;                  //strictly to help pause program execution

    vector = 0x0;

    printf("\n---Dumping IVT from bottom up---\n");
    printf("Vector\tAddress\t\n");

    for
     (
        address=IDT_001_ADDR;
        address<=IDT_255_ADDR;
        address=address+IDT_VECTOR_SZ,vector++
    )
    {
        printf("%03d\t%08p\t",vector,address);

        //IVT starts at bottom of memory, so CS is alway 0x0

        __asm__
        (
           ".intel_syntax;"
           "PUSH ES;"
           "MOV AX, 0;"
           "MOV ES,AX;"
           "MOV BX,address;"
           "MOV AX,ES:[BX];"
           "MOV ipAddr,AX;"
           "INC BX;"
           "INC BX;"
           "MOV AX,ES:[BX];"
           "MOV csAddr,AX;"
           "POP ES;"
    );
        printf("[CS:IP]=[%04X,%04X]\n",csAddr,ipAddr);
    }

    printf("press [ENTER] key to continue:");
    scanf("%c",&dummy);

    printf("\n---Overwrite IVT from top down---\n");

    /*
        Program will die somwhere around 0x4*
        Note: can get same results via DOS debug.exe -e command
    */

    for
    (
        address=IDT_255_ADDR;
        address>=IDT_001_ADDR;
        address=address-IDT_VECTOR_SZ,vector--
    )
    {
        printf("Nulling %03d\t%08p\n",vector,address);
         __asm__
        (
        ".intel_syntax;"
            "PUSH ES;"
            "MOV AX,0;"
            "MOV ES,AX;"
            "MOV BX,address;"
            "MOV ES:[BX],AX;"
            "INC BX;"
            "INC BX;"
            "MOV ES:[BX],AX;"
            "POP ES;"
    );
    }
    return;
}/*end main()------------------------------------------------------------*/

Any help would be greatly appreciated. Once again my apologies if it is something obvious.

Answer

TrueY picture TrueY · May 3, 2013

Actually you can pass C arguments to inline asm. But You have to define it after the asm code part.

In Your case something like this could work (You should add -masm=intel to the gcc's command line):

asm(
    ".intel_syntax noprefix;\n\t"
    ...
    "MOV BX,%[address];\n\t"
    ...
    ".intel_syntax prefix;\n\t"
    :: [address] "m" address, ...
    : "AX", "BX", /* all changed registers to inform compiler to save them if needed */
);

See examples in a similar question.