This question already has answers here:
Can _start be the thumb function?
(3 answers)
Closed 9 years ago.
I want to write a tiny standalone executablewithout using libc. what I need for simulating some libc functions is to have function to do syscalls using inline assembly :
int syscall(int a,...) {
return __asm__ volatile (/* DO STH HERE */);
}
I am using Linux and ARM processor.
EDIT: found the solution:
int syscall(int n,...) {
return __asm__ volatile ("mov r7,r0\nmov r0,r1\nmov r1,r2\nmov r2,r3\nswi #1\n");
}
First you need to be able to command your toolchain (gcc?) to not to include anything extra other than your code. Something like -nostartfiles -nodefaultlibs to gcc should work.
Then you need to be nice working with Linux, meaning your elf need to be loaded properly by the os, meaning it needs to have _start point visible. Below would be such an example:
void _start() __attribute__ ((naked));
void _start() {
main();
asm volatile(
"mov r7, #1\n" /* exit */
"svc #0\n"
);
}
You can then create a main which contain what you want to do.
int main() {
linuxc('X');
return 42;
}
Then doing extra with write syscall...
void linuxc(int c) {
asm volatile(
"mov r0, #1\n" /* stdout */
"mov r1, %[buf]\n" /* write buffer */
"mov r2, #1\n" /* size */
"mov r7, #4\n" /* write syscall */
"svc #0\n"
: /* output */ : [buf] "r" (&c) : "r0", "r1", "r2", "r7", "memory"
);
}
I have a more complete example of that at my github. I like the teensy one most.
Related
I recently dabbled into low level programming, and want to make a function somesyscall that accepts (CType rax, CType rbx, CType rcx, CType rdx). struct CType looks like:
/*
TYPES:
0 int
1 string
2 bool
*/
typedef struct {
void* val;
int typev;
} CType;
the function is a bit messy, but in theory should work:
#include <errno.h>
#include <stdbool.h>
#include "ctypes.h"
//define functions to set registers
#define seteax(val) asm("mov %0, %%rax" :: "g" (val) : "%rax")
#define setebx(val) asm("mov %0, %%rbx" :: "g" (val) : "%rbx")
#define setecx(val) asm("mov %0, %%rcx" :: "g" (val) : "%rcx")
#define setedx(val) asm("mov %0, %%rdx" :: "g" (val) : "%rdx")
///////////////////////////////////
#define setregister(value, register) \
switch (value.typev) { \
case 0: { \
register(*((double*)value.val)); \
break; \
} \
case 1: { \
register(*((char**)value.val)); \
break; \
} \
case 2: { \
register(*((bool*)value.val)); \
break; \
} \
}
static inline long int somesyscall(CType a0, CType a1, CType a2, CType a3) {
//set the registers
setregister(a0, seteax);
setregister(a1, setebx);
setregister(a2, setecx);
setregister(a3, setedx);
///////////////////
asm("int $0x80"); //interrupt
//fetch back the rax
long int raxret;
asm("mov %%rax, %0" : "=r" (raxret));
return raxret;
}
when I run with:
#include "syscall_unix.h"
int main() {
CType rax;
rax.val = 39;
rax.typev = 0;
CType rbx;
rbx.val = 0;
rbx.typev = 0;
CType rcx;
rcx.val = 0;
rcx.typev = 0;
CType rdx;
rdx.val = 0;
rdx.typev = 0;
printf("%ld", somesyscall(rax, rbx, rcx, rdx));
}
and compile (and run binary) with
clang test.c
./a.out
I get a segfault. However, everything seems to look correct. Am I doing anything wrong here?
After macro expansion you will have something like
long int raxret;
asm("mov %0, %%rax" :: "g" (a0) : "%rax");
asm("mov %0, %%rbx" :: "g" (a1) : "%rbx");
asm("mov %0, %%rcx" :: "g" (a2) : "%rcx");
asm("mov %0, %%rdx" :: "g" (a3) : "%rdx");
asm("int $0x80");
asm("mov %%rax, %0" : "=r" (raxret));
This doesn't work because you haven't told the compiler that it's not allowed to reuse rax, rbx, rcx, and rdx for something else during the sequence of asm statements. For instance, the register allocator might decide to copy a2 from the stack to rax and then use rax as the input operand for the mov %0, %%rcx instruction -- clobbering the value you put in rax.
(asm statements with no outputs are implicitly volatile so the first 5 can't reorder relative to each other, but the final one can move anywhere. For example, be moved after later code to where the compiler finds it convenient to generate raxret in a register of its choice. RAX might no longer have the system call return value at that point - you need to tell the compiler that the output comes from the asm statement that actually produces it, without assuming any registers survive between asm statements.)
There are two different ways to tell the compiler not to do that:
Put only the int instruction in an asm, and express all of the requirements for what goes in what register with constraint letters:
asm volatile ("int $0x80"
: "=a" (raxret) // outputs
: "a" (a0), "b" (a1), "c" (a2), "d" (a3) // pure inputs
: "memory", "r8", "r9", "r10", "r11" // clobbers
// 32-bit int 0x80 system calls in 64-bit code zero R8..R11
// for native "syscall", clobber "rcx", "r11".
);
This is possible for this simple example but not always possible in general, because there aren't constraint letters for every single register, especially not on CPUs other than x86.
// use the native 64-bit syscall ABI
// remove the r8..r11 clobbers for 32-bit mode
Put only the int instruction in an asm, and express the requirements for what goes in what register with explicit register variables:
register long rax asm("rax") = a0;
register long rbx asm("rbx") = a1;
register long rcx asm("rcx") = a2;
register long rdx asm("rdx") = r3;
// Note that int $0x80 only looks at the low 32 bits of input regs
// so `uint32_t` would be more appropriate than long
// but really you should just use "syscall" in 64-bit code.
asm volatile ("int $0x80"
: "+r" (rax) // read-write: in=call num, out=retval
: "r" (rbx), "r" (rcx), "r" (rdx) // read-only inputs
: "memory", "r8", "r9", "r10", "r11"
);
return rax;
This will work regardless of which registers you need to use. It's also probably more compatible with the macros you're trying to use to erase types.
Incidentally, if this is 64-bit x86/Linux then you should be using syscall rather than int $0x80, and the arguments belong in the ABI-standard incoming-argument registers (rdi, rsi, rdx, rcx, r8, r9 in that order), not in rbx, rcx, rdx etc. The system call number still goes in rax, though. (Use call numbers from #include <asm/unistd.h> or <sys/syscall.h>, which will be appropriate for the native ABI of the mode you're compiling for, another reason not to use int $0x80 in 64-bit mode.)
Also, the asm statement for the system-call instruction should have a "memory" clobber and be declared volatile; almost all system calls access memory somehow.
(As a micro-optimization, I suppose you could have a list of system calls that don't read memory, write memory, or modify the virtual address space, and avoid the memory clobber for them. It would be a pretty short list and I'm not sure it would be worth the trouble. Or use the syntax shown in How can I indicate that the memory *pointed* to by an inline ASM argument may be used? to tell GCC which memory might be read or written, instead of a "memory" clobber, if you write wrappers for specific syscalls.
Some of the no-pointer cases include getpid where it would be a lot faster to call into the VDSO to avoid a round trip to kernel mode and back, like glibc does for the appropriate syscalls. That also applies to clock_gettime which does take pointers.)
Incidentally, beware of the actual kernel interfaces not matching up with the interfaces presented by the C library's wrappers. This is generally documented in the NOTES section of the man page, e.g. for brk(2) and getpriority(2)
As an exercise, I'm trying to implement my own mutex library to be used in my forthcoming C programs. I'm advised to use inline assembly for this and thus have produced the following code for x86 (AT&T):
#include "mymutex.h"
void init_my_mutex(my_mutex_t *mutex){
*mutex = 1;
}
void lock_my_mutex(my_mutex_t *mutex){
asm( "movq $0, %%rax\n\t" // temp = 0
"movq $0, %%rbx\n\t"
"1: xchgq (mutex), %%rax\n\t"
"cmpq %%rax, %%rbx\n\t"
"jz 1b\n\t":::"rax","rbx");
}
void unlock_my_mutex(my_mutex_t *mutex){
*mutex = 1;
}
The problem is that I do not know how to properly address *mutex within the asm() inside lock_my_mutex. gcc -c mymutex.c -o mymutex.o compiles fine, but when try to compile my test program, count-primes.c, with gcc -pthread count-primes.c mymutex.o -o count-primes, I get the following error: relocation R_X86_64_32S against undefined symbol 'mutex' can not be used when making a PIE object; recompile with -fPIC. I have tried recompiling with -fPIC (I do not know how that should help), but I still get the same error.
My header file looks like this:
#ifndef __mymutex_h
#define __mymutex_h
// Our mutex is very simple so it is either locked
// or unlocked and we don't keep any other information
typedef long long my_mutex_t;
// Initializes a mutex to be unlocked
void init_my_mutex(my_mutex_t *mutex);
// Tries to grab a lock. The function only
// returns when the current thread holds the lock
void lock_my_mutex(my_mutex_t *mutex);
// Unlock the mutex. You don't need to check to see
// if the current thread holds the lock
void unlock_my_mutex(my_mutex_t *mutex);
#endif
In count-primes.c, I try to utilize the mutex like this:
my_mutex_t lock;
...
lock_my_mutex(&lock);
// Synchronized operation
unlock_my_mutex(&lock);
...
I suspect that the problem has to do with my addressing of mutex in the usage of asm() and think that understanding how (and why) to do this would enable me to solve the exercise. But help in any other regard is also very much appreciated.
Best,
Steffen.
Either use a memory constraint, or an input register containing the address plus a memory clobber:
With memory constraint:
void lock_my_mutex(my_mutex_t *mutex){
uint64_t tmp;
asm( "mov $0, %1\n\t"
"1: xchg %1,%0\n\t"
"test %1, %1\n\t"
"jz 1b\n\t": "+m(*mutex), "=&r"(tmp));
}
With memory clobber:
void lock_my_mutex(my_mutex_t *mutex){
uint64_t tmp;
asm volatile(
"mov $0, %0\n\t"
"1: xchg %0,(%1)\n\t"
"test %0, %0\n\t"
"jz 1b\n\t": "=&r"(tmp) : "r"(mutex) : "memory");
}
Really the memory clobber should be there either way to model the idea that, as a consequence of synchronizing with other threads, the values of other objects may change behind the compiler's back (the ones protected by the mutex). I prefer the latter approach since it doesn't imply that the asm could be removed if the mutex object is never accessed again.
Note that you can further get rid of the mov with:
void lock_my_mutex(my_mutex_t *mutex){
uint64_t tmp;
asm volatile(
"1: xchg %0,(%1)\n\t"
"test %0, %0\n\t"
"jz 1b\n\t": "=&r"(tmp) : "r"(mutex), "0"(0) : "memory");
}
FWIW I would call what you've written a spinlock (a very bad idea), not a mutex.
I am trying to write a preemptive scheduler for AVR and therefore I need some assembler code ... but I have no experience with assembler. However, I wrote all the assembler code I think I need in some C macros. At compilation I get some errors related to assembler (constant value required and garbage at and of line), which makes me think that something is not correct in my macros ...
The following macro, load_SP(some_unsigned_char, some_unsigned_char), sets the stack pointer to a known memory location ... I am keeping the location in the global struct aux_SP;
Something similar is with load_PC(...) which is loading on the stack, a program counter: "func_pointer" which is actually, as the name suggest, a pointer to a function. I assume here that the program counter as well as the function pointer are represented on 2 bytes (because the flash is small enough)
For this I am using processor register R16. In order to leave this register untouched, I am saving its value first with the macro "save_R16(tempR)" and the restoring its value with the macro "load_R16(tempR)" where "tempR" as can be seen is a global C variable.
This is simply written in a header file. This along with another two macros (not written here because of their size) "pushRegs()" and "popRegs()" which are basically pushing and then popping all processors registers is ALL my assembler code ...
What should I do to correct my macros?
// used to store the current StackPointer when creating a new task until it is restored at the
// end of createNewTask function.
struct auxSP
{
unsigned char auxSPH;
unsigned char auxSPL;
};
struct auxSP cSP = {0,0};
// used to restore processor register when using load_SP or load_PC macros to perform
// a Stack Pointer or Program Counter load.
unsigned char tempReg = 0;
////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// assembler macros begin ////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// save processor register R16
#define save_R16(tempR) \
asm volatile( \
"STS tempR, R16 \n\t" \
);
// load processor register R16
#define load_R16(tempR) \
asm volatile( \
"LDS R16, tempR \n\t" \
);
// load the Stack Pointer. Warning: Alters the processor registers
#define load_SP(new_SP_H, new_SP_L) \
asm volatile( \
"LDI R16, new_SP_H \n\t" \
"OUT SPH, R16 \n\t" \
"LDI R16, new_SP_L \n\t" \
"OUT SPL, R16 \n\t" \
);
// load the Program Counter on stack. Warning: Alters the processor registers
#define load_PC(func_pointer) \
asm volatile( \
"LDS r16, LOW(func_pointer) \n\t" \
"PUSH r16 \n\t" \
"LDS r16, HIGH(func_pointer) \n\t" \
"PUSH r16 \n\t" \
);
Your main source of reference for this should be http://www.nongnu.org/avr-libc/user-manual/inline_asm.html
Avoid using "unsigned char" - use "uint8_t", as it is shorter and more explicit. Avoid macros - use static inline functions instead whenever possible. Don't invent your own struct for auxSP, especially not using a different endian ordering than the target normally uses - just use uint16_t. Don't write things in assembly when you can write them in C. And don't split up asm statements that need to be combined together (such as preserving R16 in one statement, then using it in a second statement).
Where does that leave us?
It's a long time since I have done much AVR programming, but this might get you started:
static inline uint16_t read_SP(void) {
uint16_t sp;
asm volatile(
"in %A[sp], __SP_L__ \n\t"
"in %B[sp], __SP_H__ \n\t"
: [sp] "=r" (sp) :: );
return sp;
}
static inline void write_SP(uint16_t sp) {
asm volatile(
"out __SP_L__, %A[sp] \n\t"
"out __SP_H__, %B[sp] \n\t"
:: [sp] "r" (sp) : );
}
typedef void (*FVoid)(void);
static inline void load_PC(FVoid f) __attribute__((noreturn));
static inline void load_PC(FVoid f) {
asm volatile(
"ijmp"
:: "z" (f) );
__builtin_unreachable();
}
You will probably also want to make sure you disable interrupts before using any of these.
Here is an example of C code I did on an AVR platform. It is not macros but functions because it was more adapted for me.
void call_xxx(uint32_t address, uint16_t data)
{
asm volatile("push r15"); //has to be saved
asm volatile("ldi r18, 0x01"); //r15 will be copied to SPMCSR
asm volatile("mov r15, r18"); //copy r18 to r15 (cannot be done directly)
asm volatile("movw r0, r20"); //r1:r0 <= r21:r20 //should conatain "data" parameter
asm volatile("movw r30, r22"); //31:r30<=r23:r22 // should contain "address" parameter ...
asm volatile("sts 0x5b, r24"); //RAMPZ
asm volatile("rcall .+0"); //push PC on top of stack and never pop it
asm volatile("jmp 0x3ecb7"); //secret function
asm volatile("eor r1, r1"); //null r1
asm volatile("pop r15"); //restore value
return;
}
Also try without your \n\t this may be the "garbage at and of line"
The problem of constant value required may come from here :
#define save_R16(tempR) \
asm volatile( \
"STS tempR, R16 \n\t" \
);
For this I am less sure but STS (and other) requires an address that may need to be fixed at compile time. So depending on how you use the macro it may not compile. If tempR is not fixed, you may use functions instead of macro.
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.
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.
To try to display graphics using C, I am trying to take advantage of C's "inline assembly" feature. I get no errors during compilation, but when I try to run the program, I get this error:
Segmentation Fault: 11
Here is my code:
int main(){
asm("movb 0xc,%ah");
asm("movb $1,%al");
asm("movw $5,%cx");
asm("movw $5,%dx");
asm("int $0xc");
return 0;
}
Constructive criticism appreciated, insults not.
Thanks!
First, it looks like you're trying to use BIOS interrupts to do the graphics, but the graphics interrupt is int 10h (0x10), not 0xc, so you want to call int $0x10.
Second, you can't call most BIOS interrupts from within 32-bit or 64-bit Linux or Windows programs, so make sure you're compiling this for DOS. Otherwise, calling the invoke interrupt opcode on a BIOS interrupt will crash your program. And if you run a newer version of Windows, you'll probably still have to run your compiled program inside of an emulator like DOSBox for it to work properly.
Finally, GCC inline assembly has a certain format to it:
__asm__ __volatile__ (
assembler template
: output operands /* optional */
: input operands /* optional */
: list of clobbered registers /* optional */
);
So for example:
int main()
{
/* Set video mode: */
__asm__ __volatile__ (
"movb $0x0, %%ah \n\
movb $0x13, %%al \n\
int $0x10"
:
:
:"ax"
);
/* Draw pixel of color 1 at 5,5: */
__asm__ __volatile__ (
"movb $0xC,%%ah \n\
movb $1, %%al \n\
movw $5, %%cx \n\
movw $5, %%dx \n\
int $0x10"
:
:
:"ax","cx","dx"
);
/* Reset video mode: */
__asm__ __volatile__ (
"movb $0x0, %%ah \n\
movb $0x03, %%al \n\
int $0x10"
:
:
:"ax"
);
return 0;
}
But the optional fields are only really useful if you're writing functions in assembly language and want to pass in arguments from your C code.
Also, I don't have DJGPP and a DOS installation handy, so I can't test any of this code to make sure it works with the 32-bit protected mode binaries it generates, but hopefully I've hit the nail close enough on the head that you can handle the rest yourself. Good luck!