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

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.

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?

How to pass variables to intel format inline asm code compiled with gcc

I would like to ask some help form You! I have a project with a lot of C source. Most of them compiled with gcc, but some compiled with Intel compiler. This later codes have a lot of inline asm codes in Microsoft's MASM format. I would like to compile the whole project with gcc and modify as few code as I can. So I wrote a perl script which converts the intel format inline asm to GAS format. (BTW: I compile to 32 bit on a 64 bit Linux machine).
My problem that I have to specify for gcc that in the inline asm("...") which C variables are passed to the code adding the :: [var1] "m" var1, [var2] "m" var2, ... line at the end.
Is it a way to avoid this explicit specification?
My tryings:
The dummy test C code is simply replaces 4 characters the destination char array with the elements of the source char array (I know this is not the best way to do it. It is just a stupid example).
In the original function there is no explicit specification, but it can be compiled with Intel compiler (shame on me, but I did not test this, but it should work with Intel compiler as I made it based on the real code). LOOP label is used a lot of times, even in the same C source file.
#include <stdio.h>
void cp(char *pSrc, char *pDst) {
__asm
{
mov esi, pSrc
mov edi, pDst
mov edx, 4
LOOP:
mov al, [esi]
mov [edi], al
inc esi
inc edi
dec edx
jnz LOOP
};
}
int main() {
char src[] = "abcd";
char dst[] = "ABCD";
cp(src, dst);
printf("SRC: '%s', DST: '%s'\n", src, dst);
return 0;
}
Result is: SRC: 'abcd', DST: 'abcd'
The working converted cp code is (compiled with gcc).
GAS (AT&T) format (compiled: gcc -ggdb3 -std=gnu99 -m32 -o asm asm.c)
void cp(char *pSrc, char *pDst) {
asm(
"mov %[pSrc], %%esi\n\t"
"mov %[pDst], %%edi\n\t"
"mov $4, %%edx\n\t"
"LOOP%=:\n\t"
"mov (%%esi), %%al\n\t"
"mov %%al, (%%edi)\n\t"
"inc %%esi\n\t"
"inc %%edi\n\t"
"dec %%edx\n\t"
"jnz LOOP%=\n\t"
: [pDst] "=m" (pDst)
: [pSrc] "m" (pSrc)
: "esi", "edi", "edx", "al"
);
}
Intel format (compiled: gcc -ggdb3 -std=gnu99 -m32 -masm=intel -o asm asm.c)
void cp(char *pSrc, char *pDst) {
asm(".intel_syntax noprefix\n\t");
asm(
"mov esi, %[pSrc]\n\t"
"mov edi, %[pDst]\n\t"
"mov edx, 4\n\t"
"LOOP%=:\n\t"
"mov al, [esi]\n\t"
"mov [edi], al\n\t"
"inc esi\n\t"
"inc edi\n\t"
"dec edx\n\t"
"jnz LOOP%=\n\t"
: [pDst] "=m" (pDst)
: [pSrc] "m" (pSrc)
: "esi", "edi", "edx", "al"
);
asm(".intel_syntax prefix");
}
Both codes are working, but it needs some code modification (inserting the '%' characters, collecting the variables, modifying the jump labels and jump functions).
I also tried this version:
void cp(char *pSrc, char *pDst) {
asm(".intel_syntax noprefix\n\t");
asm(
"mov esi, pSrc\n\t"
"mov edi, pDst\n\t"
"mov edx, 4\n\t"
"LOOP:\n\t"
"mov al, [esi]\n\t"
"mov [edi], al\n\t"
"inc esi\n\t"
"inc edi\n\t"
"dec edx\n\t"
"jnz LOOP\n\t"
);
asm(".intel_syntax prefix");
}
But it drops
gcc -ggdb3 -std=gnu99 -masm=intel -m32 -o ./asm.exe ./asm.c
/tmp/cc2F9i0u.o: In function `cp':
/home/TAG_VR_20130311/vr/vr/slicecodec/src/./asm.c:41: undefined reference to `pSrc'
/home/TAG_VR_20130311/vr/vr/slicecodec/src/./asm.c:41: undefined reference to `pDst'
collect2: ld returned 1 exit status
Is there a way to avoid the definition of the input arguments and avoid the modifications of local labels?
ADDITION
I tried to use global variable. For this g constrain has to be used instead of m.
char pGlob[] = "qwer";
void cp(char *pDst) {
asm(".intel_syntax noprefix\n\t"
"mov esi, %[pGlob]\n\t"
"mov edi, %[pDst]\n\t"
"mov edx, 4\n\t"
"LOOP%=:\n\t"
"mov al, [esi]\n\t"
"mov [edi], al\n\t"
"inc esi\n\t"
"inc edi\n\t"
"dec edx\n\t"
"jnz LOOP%=\n\t"
".intel_syntax prefix" : [pDst] "=m" (pDst) : [pGlob] "g" (pGlob)
: "esi", "edi", "edx", "al");
}
ADDITION#2
I tried
"lea esi, pGlob\n\t" // OK
"lea esi, %[_pGlob]\n\t" // BAD
//"lea esi, pGlob_not_defined\n\t" // BAD
//gcc failed with: undefined reference to `pGlob_not_defined'
compiled to
lea esi, pGlob
lea esi, OFFSET FLAT:pGlob // BAD
//compilation fails with: Error: suffix or operands invalid for `lea'
It seems that only function local variables has to be defined. Global variable may be added to the trailer, but not really necessary. Both are working:
"mov esi, pGlob\n\t" // OK
"mov esi, %[_pGlob]\n\t" // OK
compiled to
mov esi, OFFSET FLAT:pGlob
mov esi, OFFSET FLAT:pGlob
I defined a function local variable. It has to be defined in the constraint part:
void cp(char *pDst) {
char pLoc[] = "yxcv";
asm(".intel_syntax noprefix\n\t"
...
//"mov esi, pLoc\n\t" // BAD
"mov esi, %[_pLoc]\n\t" // OK, 'm' BAD
...
".intel_syntax prefix" : [_pDst] "=m" (pDst) : [_pLoc] "g" (pLoc)
: "esi", "edi", "edx", "al");
Unfortunately it should be determined what are the global and what are the local variables. It is not easy as the asm code can be defined in C macros and even the surrounding function is not definite. I think only the precompiler has enough information to this. Maybe the code has to be precompiled with gcc -E ....
I realized that not defining the output in the constraint part, some code can be eliminated by the optimizer.
TIA!
Yes, you do need to specify the registers explicitly. GCC will not do that for you. And you can't (generally) put C variable names inside the ASM string.
Your final code block looks perfectly good, to me, but in GCC you don't need to choose which registers to use yourself. You should also use the volatile keyword to prevent the compiler thinking the code doesn't do anything given that it has no outputs.
Try this:
char pGlob[] = "qwer";
void cp(char *pDst) {
asm volatile (".intel_syntax noprefix\n\t"
"mov edx, 4\n\t"
"LOOP%=:\n\t"
"mov al, [%[pGlob]]\n\t"
"mov [%[pDst]], al\n\t"
"inc %[pGlob]\n\t"
"inc %[pDst]\n\t"
"dec edx\n\t"
"jnz LOOP%=\n\t"
".intel_syntax prefix" :: [pGlob] "g" (pGlob), [pDst] "g" (pDst) : "edx");
}
This way the compiler deals with loading the variables and chooses the registers for you (thereby eliminating a pointless copy from one register to another). Ideally you'd also eliminate the explicit use of edx, but it's not really necessary here.
Of course, in this silly example I would just recode the whole thing in C and let the compiler do its job.

LLVM complains about assembler error "Unexpected token in memory operand"

I'm doing a study assignment to measure memory access time on my machine.
To determine the clock cycles on our machines, we have been given the following C snippet:
static inline void getcyclecount(uint64_t* cycles)
{
__asm __volatile(
"cpuid # force all previous instruction to complete\n\t"
"rdtsc # TSC -> edx:eax \n\t"
"movl %%edx, 4(0) # store edx\n\t"
"movl %%eax, 0(0) # store eax\n\t"
: : "r"(cycles) : "eax", "ebx", "ecx", "edx");
}
However, when I try to compile this (XCode 4, using "Apple LLVM Compiler 2.1"), it results twice in the error "Unexpected token in memory operand" at the "\t" of the rdtsc resp. first movl instruction line.
I know basic assembler, but have no clue about the C inline assembler format.
Does anyone of you know what could be the issue with this code?
Thanks!
Assuming this is GCC inline assembly syntax, you're missing a % in the memory operand:
__asm __volatile(
"cpuid # force all previous instruction to complete\n\t"
"rdtsc # TSC -> edx:eax \n\t"
"movl %%edx, 4(%0) # store edx\n\t"
"movl %%eax, 0(%0) # store eax\n\t"
: : "r"(cycles) : "eax", "ebx", "ecx", "edx");

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