Calling printf from inline ASM (X64) - c

I have this code:
#include <stdio.h>
#include <stdint.h>
int main(void){
char *fmt = "%s";
char *s = "Hello world!\n";
//gcc -m32 test.c
#ifdef __i386__
int32_t ret;
__asm__ __volatile__ (
"push %1\n\t"
"push %2\n\t"
"movl $2, %%eax\n\t"
"call printf\n\t"
"movl %0, %%eax"
: "=r" (ret)
: "r" (s), "r" (fmt)
:
);
#endif
//gcc -m64 test.c
#ifdef __x86_64__
int64_t ret;
__asm__ __volatile__ (
"push %1\n\t"
"push %2\n\t"
"movq $2, %%rax\n\t"
"call printf\n\t"
"movq %0, %%rax"
: "=r" (ret)
: "r" (s), "r" (fmt)
:
);
#endif
return ret;
}
The x86 version works as expected, but the x64 version segfaults. Why is it segfault-ing?

The 64-bit ABI uses registers (RDI, RSI, RDX, RCX, R8 and R9) instead of the stack for argument passing. So the code should be:
movl %2,%%rdi
movl %1,%%rsi
call printf
movq %0,%%rax

I think this is relative to 64bit EABI. You can find some information on that SO question.

Related

C Assembly : Return value from %eax beyond jump instruction error: expected ‘)’ before ‘:’ token

In following c function
#1
int check()
{
__asm__ __volatile__ (
<snip some activity that has a jump to not_supported>
"movl $1, %eax \n\t" \
"jmp done \n\t" \
"not_supported:\n\t" \
"movl $0, %eax \n\t" \
“done:\n\t”
);
}
Return value is stored in the eax register
This compiles fine on
gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
But complains in other place due to werror enforcement
error: no return statement in function returning non-void [-Werror=return-type]
So to make it acceptable to gcc with werror I added a stack variable as a return value to #1
int check()
{
int ret_value =0;
__asm__ __volatile__ (
<snip some activity that has a jump to not_supported>
"movl $1, %0 \n\t" : "=a"(ret_value) :: \
"jmp done \n\t" \
"not_supported:\n\t" \
"movl $0, %0 \n\t" : "=a"(ret_value) :: \
"done:\n\t"
);
return ret_value;
}
The gcc doesn’t allow this to compile even with non werror case :
: error: expected ‘)’ before ‘:’ token
"movl $0, %0 \n\t" : "=r"(ret_value) :: \
This complains at the first : in the movl instruction
I tried with the “=r” register operand constraints for output as well but still it doesn’t compile. I also tried explicitly giving clobber registers as "eax" but that also doesn't help.
It seems gcc complains about ret_value modification after the jmp .
Other thing I tried was #1 with another mov from eax to ret_val which logically didn’t make sense to me.
(What I mean is adding a movl instruction after the done: that moves value of %eax to %0 which is ret_val)
And that didn’t compile either.
Any thing I am missing here ?
#margaretBloom's suggestion helped. I removed multiple mentions of output operands and just kept one at the end. This helped compile but here's the disassembled output looks like :
0x000055555555519f <+53>: jmp 0x5555555551a6 <dummy_funct+60>
0x00005555555551a1 <+55>: mov $0x0,%eax
0x00005555555551a6 <+60>: mov %edx,-0x4(%rbp)
0x00005555555551a9 <+63>: mov -0x4(%rbp),%eax
0x00005555555551ac <+66>: pop %rbp
0x00005555555551ad <+67>: retq
Here the compiler is trying to write the stack variable contents to eax . Thus overwriting the real output that was originally stored in the eax.
With further exploration and bug fixes following thing works :
"movl $1, %%eax \n\t" \
"movl %%eax, %0 \n\t" \
"jmp done \n\t" \
not_supported:\n\t" \
"movl $0, %%eax \n\t" \
"movl %%eax, %0 \n\t" \
"done:\n\t" \
: "=r" (ret_value)
:
:"%eax", "%ebx", "%ecx"
);
The trick was to record the results in the eax and then copy those to the return value explicitly along with appropriate clobbering. The other thing was provided register operands rather than the registers themselves for the instructions.

segment fault after modifying SEGMENT_START in ldscript

I write a program which does not use glibc,as follow
char *str = "hello world!\n";
void print()
{
asm("movl $13, %%edx \n\t"
"movl %0, %%ecx \n\t"
"movl $0, %%ebx \n\t"
"movl $4, %%eax \n\t"
"int $0x80 \n\t"
::"m"(str):"edx", "ecx", "ebx");
}
void exit()
{
asm("movl $42, %ebx \n\t"
"movl $1, %eax \n\t"
"int $0x80 \n\t"
);
}
void nomain()
{
// print();
while(1);
exit();
}
this program can run in ubuntu18.04(linux kernel 4.15) when use gcc default ldscript,then I use my own ldscript,as follow
ENTRY(nomain)
SECTIONS
{
. = 0x200000 + SIZEOF_HEADERS; /* SEGMENT_START is 0x200000 */
tinytext : {*(.text) *(.data*) *(.rodata) }
/DISCARD/ : {*(.comment)}
}
when SEGMENT_START is 0x200000,program can run,but when SEGMENT_START is 0x100000,segment fault happens.
I repeat that in ubuntu5.10(linux kernel 2.6.12),no segmnet fault,I think errors maybe happened in loading time,and I try to find reason in linux kernel 4.15,sorry I can`t,can anyone tell me what cause segment fault?

Impelementing atomic CAS in gcc inline

I've been trying to implement a gcc inline function (AT&T assembly) that will perform an atomic CAS operation, but I can't get it to work - the return value is always getting messed up.
I've tried 2 different approaches, each seems to have its own misbehaviours:
1.
static inline int
cas(volatile void * addr, int expected, int newval)
{
int result = 1;
asm volatile("lock; cmpxchgl %3, (%2)\n\t"
"pushfl\n\t"
"popl %%ebx\n\t"
"andl $0x40, %%ebx\n\t"
"cmpl $0x0, %%ebx\n\t"
"jnz res%=\n\t"
"movl $0, %0\n\t"
"res%=:\n\t"
: "=m"(result)
: "a"(expected), "b"(addr), "r"(newval)
: "memory");
return result;
}
2.
static inline int cas(volatile void * addr, int expected, int newval) {
int ret = 1;
asm volatile("lock; cmpxchgl %3, (%2)\n\t"
"jz cas_success%=\n\t"
"movl $0, %0\n\t"
"cas_success%=:\n\t"
: "=m"(ret)
: "a"(expected), "b"(addr), "r"(newval)
: "memory");
return ret;
}
But neither work, could anyone point me at the problem with one of the implementations?
Thanks

Insert a string into register inline ASM with GCC

I'm working on a code that checks if the program is running under VM or VPC in C and I have some errors in the inline ASM at compile-time.
This is my code so far:
bool IsInsideVPC()
{
bool rc = false;
try
{
__asm__(
"push %ebx\n\t"
"movl $0, %ebx\n\t" // Flag
"movl $1, %eax"); // VPC function number
// call VPC
asm __volatile__ (".byte 0x0F");
asm __volatile__ (".byte 0x3F");
asm __volatile__ (".byte 0x07");
asm __volatile__ (".byte 0x0B");
__asm__(
"test %ebx, %ebx\n\t"
"movl $1, $rc\n\t" // Flag
"pop %ebx");
}
catch (...)
{
// The except block shouldn't get triggered if VPC is running!!
}
return rc;
}
bool IsInsideVMWare()
{
bool rc = false;
try
{
__asm__(
"push %edx\n\t"
"push %ecx\n\t" // Flag
"push %ebx\n\t"
"movl 'VMXh', %eax\n\t"
"movl $0, %ebx\n\t"
"movl $10, %ecx\n\t"
"movl 'VX', %edx\n\t"
"in %eax, %dx\n\t"
"cmp %ebx, 'VMXh'\n\t"
"movl $1, $rc\n\t"
"pop %ebx\n\t"
"pop %ecx\n\t"
"pop %edx");
}
catch (...)
{
rc = false;
}
return rc;
}
Ofcourse after all this, there is the main function that runs eveything, checks the results and outputs an answer.
I didn't write the original code, but I did changed it to the GCC syntax.
I'm getting errors that I think are related to the way I insert a string into a register.

How to add a counter in gcc asm?

In the linux kernel code, when a spinlock is locked, the spin_lock function will spinning. The code of spin_lock is below:
static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
{
int inc = 0x00010000;
int tmp;
asm volatile(LOCK_PREFIX "xaddl %0, %1\n"
"movzwl %w0, %2\n\t"
"shrl $16, %0\n\t"
"1:\t"
"cmpl %0, %2\n\t"
"je 2f\n\t"
"rep ; nop\n\t"
"movzwl %1, %2\n\t"
/* don't need lfence here, because loads are in-order */
"jmp 1b\n"
"2:"
: "+r" (inc), "+m" (lock->slock), "=&r" (tmp)
:
: "memory", "cc");
}
My question is:
How can I add a time counter to monitor the spinning time of the lock?Please give me some advice.
You can use rdtsc time stamp counter to measure the interval ,you can view the below links http://www.xml.com/ldd/chapter/book/ch06.html
http://wiki.osdev.org/Inline_Assembly/Examples

Resources