Im trying to run the following code, which writes to a port.
void write(uint8_t size, uint8_t data, uint16_t port_number){
char command[] = "out_ %0, %1";
command[3] = size; //outb, outw or outl
__asm__ volatile(command: : "a"(data), "Nd"(port_number) );
}
i get tet the followng error message:
test.cpp:32:22: error: expected string-literal before ‘command’
__asm__ volatile(command : : "a"(data), "Nd"(port_number) );
if i try running this line:
__asm__ volatile("outb %0, %1": : "a"(data), "Nd"(port_number) );
it compiles without problem.
Now, i know i can solve this by creating 3 versions of the write function, one for each form of 'out', but is there a better way of solving this problem without copy-pasting code?
The first argument of __asm__ volatile(), AsmTemplate, must be a string literal.
For each output sizes, you just need to call the function with the corresponding literal. You can use a branching here using if-else or switch-case:
void write(uint8_t size, uint8_t data, uint16_t port_number){
char command[] = "out_ %0, %1";
command[3] = size; //outb, outw or out
switch(size) {
case 'b': __asm__ volatile("outb %0, %1": :"a"(data), "Nd"(port_number) ); break;
case 'w' : __asm__ volatile("outw %0, %1": :"a"(data), "Nd"(port_number) ); break;
case 'l' : __asm__ volatile("outl %0, %1": :"a"(data), "Nd"(port_number) ); break;
}
}
Add the cases to cover every possible 'size' values.
You can shorten each line by using a #define with size as its argument
Related
I was trying to compile ODE(Open Dynamics Engine) physics C++ library for Android Native application on Android Studio.
When i tried to build it, it gave me some error telling that some inline ASM code is not correct as they are written for INTEL processor syntax. This are mostly to get CPU clock frequency for physics simulation purpose.
(Editor's note: this x86 GNU C inline asm is inefficient and not even safe or portable. See How to get the CPU cycle count in x86_64 from C++? for correct ways to use i386 / x86-64 rdtsc.)
static inline void getClockCount (unsigned long cc[2])
{
#ifndef X86_64_SYSTEM
asm volatile (
"rdtsc\n"
"movl %%eax,(%%esi)\n"
"movl %%edx,4(%%esi)\n"
: : "S" (cc) : "%eax","%edx","cc","memory");
#else
asm volatile (
"rdtsc\n"
"movl %%eax,(%%rsi)\n"
"movl %%edx,4(%%rsi)\n"
: : "S" (cc) : "%eax","%edx","cc","memory");
#endif
}
static inline void serialize()
{
#ifndef X86_64_SYSTEM
asm volatile (
"mov $0,%%eax\n"
"push %%ebx\n"
"cpuid\n"
"pop %%ebx\n"
: : : "%eax","%ecx","%edx","cc","memory");
#else
asm volatile (
"mov $0,%%rax\n"
"push %%rbx\n"
"cpuid\n"
"pop %%rbx\n"
: : : "%rax","%rcx","%rdx","cc","memory");
#endif
}
static inline double loadClockCount (unsigned long a[2])
{
double ret;
#ifndef X86_64_SYSTEM
asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) :
"cc","memory");
#else
asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) :
"cc","memory");
#endif
return ret;
}
I don't know how to do same for ARM? Any help?
I'm working on a simple real-mode OS in c++. I can't figure out how to print strings, though. The following code works when it's in the bootloader, but not when it's in the kernel.
__asm__ __volatile__(".code16gcc \n");
__asm__ __volatile__ ("xor ax, ax\n");
__asm__ __volatile__ ("mov ds, ax\n");
__asm__ __volatile__("jmp main \n");
void printf(const char* str)
{
while(*str)
{
__asm__ __volatile__("int 0x10" : : "a"(0x0e00 | *str), "b"(0x0007));
++str;
}
}
void main(){
printf("Hi!");
}
I'm sure it's because the ds register it set to 0, but the code is actually at 0x7E00 (that's where the bootloader puts it). I've tried setting ds to 0x7E0, which should cause it to load data correctly because 0x7E0 * 16 = 0x7E00, but it still doesn't work. It's probably just some silly mistake, but I would appreciate some help. If it matters, here is my bootloader code:
__asm__(".code16gcc \n");
void main(){
__asm__ __volatile__("mov al, 0x02 \n");
__asm__ __volatile__("xor ah, ah \n");
__asm__ __volatile__("int 0x10 \n");
__asm__ __volatile__("xor ax, ax \n");
__asm__ __volatile__("mov es, ax \n");
__asm__ __volatile__("mov bx, 0x7E00 \n");
__asm__ __volatile__("mov al, 0x03 \n");
__asm__ __volatile__("mov ch, 0x00 \n");
__asm__ __volatile__("mov cl, 0x02 \n");
__asm__ __volatile__("mov dh, 0x00 \n");
__asm__ __volatile__("mov ah, 0x02 \n");
__asm__ __volatile__("int 0x13 \n");
__asm__ __volatile__("jmp 0:0x7E00 \n");
}
I am compiling a piece of asm code for android:
static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
{
__asm__ __volatile__ (
"cpuid"
: "=a" (*a) ,
"=b" (*b) ,
"=c" (*c) ,
"=d" (*d)
: "0" (function)) ;
}
The APP_ABI is set to 'all':
APP_ABI := all
The compiling failed when come to x86:
$ ndk-build
[armeabi-v7a] Gdbserver : [arm-linux-androideabi-4.6] libs/armeabi-v7a/gdbserver
[armeabi-v7a] Gdbsetup : libs/armeabi-v7a/gdb.setup
[armeabi] Gdbserver : [arm-linux-androideabi-4.6] libs/armeabi/gdbserver
[armeabi] Gdbsetup : libs/armeabi/gdb.setup
[x86] Gdbserver : [x86-4.6] libs/x86/gdbserver
[x86] Gdbsetup : libs/x86/gdb.setup
[mips] Gdbserver : [mipsel-linux-android-4.6] libs/mips/gdbserver
[mips] Gdbsetup : libs/mips/gdb.setup
[armeabi-v7a] Compile thumb : hello-jni <= CpuArch.c
[armeabi-v7a] SharedLibrary : libhello-jni.so
[armeabi-v7a] Install : libhello-jni.so => libs/armeabi-v7a/libhello-jni.so
[armeabi] Compile thumb : hello-jni <= CpuArch.c
[armeabi] SharedLibrary : libhello-jni.so
[armeabi] Install : libhello-jni.so => libs/armeabi/libhello-jni.so
[x86] Compile : hello-jni <= CpuArch.c
D:/adt/ndk/samples/hello-jni/jni/CpuArch.c: In function 'MyCPUID':
D:/adt/ndk/samples/hello-jni/jni/CpuArch.c:75:3: error: inconsistent operand constraints in an 'asm'
/cygdrive/d/adt/ndk/build/core/build-binary.mk:391: recipe for target '/cygdrive/d/adt/ndk/samples/hello-jni/obj/local/x86/objs-debug/hello-jni/CpuArch.o' failed
make: *** [/cygdrive/d/adt/ndk/samples/hello-jni/obj/local/x86/objs-debug/hello-jni/CpuArch.o] Error 1
I don't have much experience in asm. And the error msg seems not enough to find a solution. :(
BTW,the compiling is made in win7 using cygwin.
Full version:
static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
{
#ifdef USE_ASM
#ifdef _MSC_VER
UInt32 a2, b2, c2, d2;
__asm xor EBX, EBX;
__asm xor ECX, ECX;
__asm xor EDX, EDX;
__asm mov EAX, function;
__asm cpuid;
__asm mov a2, EAX;
__asm mov b2, EBX;
__asm mov c2, ECX;
__asm mov d2, EDX;
*a = a2;
*b = b2;
*c = c2;
*d = d2;
#else
__asm__ __volatile__ (
"cpuid"
: "=a" (*a) ,
"=b" (*b) ,
"=c" (*c) ,
"=d" (*d)
: "0" (function)) ;
#endif
#else
int CPUInfo[4];
__cpuid(CPUInfo, function);
*a = CPUInfo[0];
*b = CPUInfo[1];
*c = CPUInfo[2];
*d = CPUInfo[3];
#endif
}
This code is based up something I wrote in this Stackoverflow answer. One has to be careful to preserve %ebx register on some x86 based architectures/ABI. %ebx is used to relocate code (shared object etc) when position independent code (-fPIC gcc option) is being generated. The code below avoids using =b in the extended assembler output and uses a register the compiler knows is free and usable. %ebx is preserved by swapping it to the free register before and after the call to cpuid. I've also fixed a small gotchya bug related to the %ecx register. I clear it to 0 ("c"(0)) since on some architectures failure to do so will result in stale values being returned by cpuid.
static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
{
#if defined(__i386__)
__asm__ __volatile__ (
"xchgl\t%%ebx, %k1\n\t" \
"cpuid\n\t" \
"xchgl\t%%ebx, %k1\n\t"
: "=a"(*a), "=&r"(*b), "=c"(*c), "=d"(*d)
: "a"(function), "c"(0));
#elif defined(__x86_64__)
__asm__ __volatile__ (
"xchgq\t%%rbx, %q1\n\t" \
"cpuid\n\t" \
"xchgq\t%%rbx, %q1\n\t"
: "=a"(*a), "=&r"(*b), "=c"(*c), "=d"(*d)
: "a"(function), "c"(0));
#else
#error "Unknown architecture."
#endif
}
I'm trying to compile the following wrapper function for a system call for my Operating Systems class and I keep getting the following compilation error.
Just to clarify, this code is from a HW assignment where we needed to add some functionality to the task_struct. It's Linux 2.4 running on a VM.
syscall_files.h: In function `get_all_events_number`:
syscall_files.h:58: parse error before ')' token
int get_all_events_number(){
long __res;
__asm__ volatile (
"movl $245, %%eax;"
"int $0x80;"
"movl %%eax, %0"
: "=m" (__res)
: "%eax"
); << line 58
if((unsigned long)(__res) >= (unsigned long)(-125)) {
errno = -(__res);
__res = -1;
}
return (int)(__res);
}
Can anyone see the the problem? I've been trying to figure it out for the past 30 mintues and I have no idea what's wrong.
Did I convert this correctly?
Original VS C++ version:
_TEB *pTeb = NULL;
_asm
{
mov eax, fs:[0x18];
mov pTeb, eax;
}
My attempt (GCC):
_TEB *pTeb = NULL;
asm ("movl %%fs:0x18, %%eax\n\t"
"movl %%eax, %0"
: "=rm" (pTeb) : : "%eax");
If you need GCC syntax for Windows-related code, a good source to check is ReactOS sources. Here's their implementation of NtCurrentTeb() (with irrelevant parts removed):
unsigned long __readfsdword(const unsigned long Offset)
{
unsigned long value;
__asm__ __volatile__("movl %%fs:%a[Offset], %k[value]" : [value] "=r" (value) : [Offset] "ir" (Offset));
return value;
}
struct _TEB * NtCurrentTeb(VOID)
{
return (PTEB)__readfsdword(0x18);
}