segment fault after modifying SEGMENT_START in ldscript - c

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?

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.

Link script .lds file hasn't effect but compile successfully

Here is the code
//hello.c
char* str = "Hello world!\n";
void print()
{
asm(
"mov $13, %%rdx \n\t"
"mov %0, %%rcx \n\t"
"mov $0, %%rbx \n\t"
"mov $4, %%rax \n\t"
"int $0x80 \n\t"
::"r"(str):"rdx","rcx","rbx");
}
void exit()
{
asm(
"mov $42, %rbx \n\t"
"mov $1, %rax \n\t"
"int $0x80 \n\t"
);
}
void hello()
{
print();
exit();
}
And here is the link script hello.lds
ENTRY(hello)
SECTIONS
{
. = 0X08048000 + SIZEOF_HEADERS;
tinytext : {*(.text) *(.data) *(.rodata)}
/DISCARD/ : {*(.comment)}
}
I use the following command to compile and build an ELF file, and I want to combine .text, .data and .rodata to one .tinytext, what's more, I want to discard .comment.
gcc -c -fno-builtin hello.c
ld -static -T hello.lds -o hello hello.o
But the thing is that this can not work, when using objdump or readelf, I find the .text .data and .rodata still exist. What's more, the ELF file size enlarged from 1.6KB to 296KB(What I intended for is that the size may be less than 1KB).
Is there any problem of my operation?
And when I change the addr from 0x08048000 to 0x00000000, I find the size decrease from 296KB to a relatively small size like 1.1KB, can anyone explain it?
Thanks for any help.
After the help from Jester and Peter Cordes, I solve the problem. This problem comes from the wrong use of lds. In 64bit program, the general base address is not 0x08048000 but 0x400000. Changing that address, I successfully decrease the size of ELF file to 700 bytes and the result of objdump is just what I want to have.

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.

Calling printf from inline ASM (X64)

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.

syscall from within GCC inline assembly [duplicate]

This question already has answers here:
How to invoke a system call via syscall or sysenter in inline assembly?
(2 answers)
Closed 3 years ago.
is it possible to write a single character using a syscall from within an inline assembly block? if so, how? it should look "something" like this:
__asm__ __volatile__
(
" movl $1, %%edx \n\t"
" movl $80, %%ecx \n\t"
" movl $0, %%ebx \n\t"
" movl $4, %%eax \n\t"
" int $0x80 \n\t"
::: "%eax", "%ebx", "%ecx", "%edx"
);
$80 is 'P' in ascii, but that returns nothing.
any suggestions much appreciated!
You can use architecture-specific constraints to directly place the arguments in specific registers, without needing the movl instructions in your inline assembly. Furthermore, then you can then use the & operator to get the address of the character:
#include <sys/syscall.h>
void sys_putc(char c) {
// write(int fd, const void *buf, size_t count);
int ret;
asm volatile("int $0x80"
: "=a"(ret) // outputs
: "a"(SYS_write), "b"(1), "c"(&c), "d"(1) // inputs
: "memory"); // clobbers
}
int main(void) {
sys_putc('P');
sys_putc('\n');
}
(Editor's note: the "memory" clobber is needed, or some other way of telling the compiler that the memory pointed-to by &c is read. How can I indicate that the memory *pointed* to by an inline ASM argument may be used?)
(In this case, =a(ret) is needed to indicate that the syscall clobbers EAX. We can't list EAX as a clobber because we need an input operand to use that register. The "a" constraint is like "r" but can only pick AL/AX/EAX/RAX. )
$ cc -m32 sys_putc.c && ./a.out
P
You could also return the number of bytes written that the syscall returns, and use "0" as a constraint to indicate EAX again:
int sys_putc(char c) {
int ret;
asm volatile("int $0x80" : "=a"(ret) : "0"(SYS_write), "b"(1), "c"(&c), "d"(1) : "memory");
return ret;
}
Note that on error, the system call return value will be a -errno code like -EBADF (bad file descriptor) or -EFAULT (bad pointer).
The normal libc system call wrapper functions check for a return value of unsigned eax > -4096UL and set errno + return -1.
Also note that compiling with -m32 is required: the 64-bit syscall ABI uses different call numbers (and registers), but this asm is hard-coding the slow way of invoking the 32-bit ABI, int $0x80.
Compiling in 64-bit mode will get sys/syscall.h to define SYS_write with 64-bit call numbers, which would break this code. So would 64-bit stack addresses even if you used the right numbers. What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code? - don't do that.
IIRC, two things are wrong in your example.
Firstly, you're writing to stdin with mov $0, %ebx
Second, write takes a pointer as it's second argument, so to write a single character you need that character stored somewhere in memory, you can't write the value directly to %ecx
ex:
.data
char: .byte 80
.text
mov $char, %ecx
I've only done pure asm in Linux, never inline using gcc, you can't drop data into the middle of the assembly, so I'm not sure how you'd get the pointer using inline assembly.
EDIT: I think I just remembered how to do it. you could push 'p' onto the stack and use %esp
pushw $80
movl %%esp, %%ecx
... int $0x80 ...
addl $2, %%esp
Something like
char p = 'P';
int main()
{
__asm__ __volatile__
(
" movl $1, %%edx \n\t"
" leal p , %%ecx \n\t"
" movl $0, %%ebx \n\t"
" movl $4, %%eax \n\t"
" int $0x80 \n\t"
::: "%eax", "%ebx", "%ecx", "%edx"
);
}
Add: note that I've used lea to Load the Effective Address of the char into ecx register; for the value of ebx I tried $0 and $1 and it seems to work anyway ...
Avoid the use of external char
int main()
{
__asm__ __volatile__
(
" movl $1, %%edx \n\t"
" subl $4, %%esp \n\t"
" movl $80, (%%esp)\n\t"
" movl %%esp, %%ecx \n\t"
" movl $1, %%ebx \n\t"
" movl $4, %%eax \n\t"
" int $0x80 \n\t"
" addl $4, %%esp\n\t"
::: "%eax", "%ebx", "%ecx", "%edx"
);
}
N.B.: it works because of the endianness of intel processors! :D

Resources