Tell the compiler to translate a certain instruction differently? - c

I'm using armcc and arm-gcc for compiling my project for an ARM968 processor.
When returning form a function call, the returning instruction is as follows:
Pop {ri-rj, pc}
All the pushed registers are popped in the same instruction. I want to change the instruction above into something like this:
Pop {ri-rj}
Pop {pc}
Can I instruct the assembler or the compiler to adhere to the rule above in any of the ARM tool chains when using Pop?

Depending on the exact nature of the problem, and whether you're critically dependent on a handful of newer instructions, another possibility might be to compile for ARMv4T. Prior to ARMv5T, ldm into the PC was not interworking, so the compiler won't emit that form of return instruction for a v4T target. For some simple test code, compiling with -march=armv5t generates a stack frame thus:
8: e92d4070 push {r4, r5, r6, lr}
...
4c: d8bd8070 pople {r4, r5, r6, pc}
whereas compiling the same thing with -march=armv4t uses the same prologue but with an indirect return sequence (the above was a conditional return from inside a loop, now it's also moved out to the end of the function):
48: da000006 ble 68 <func+0x68>
...
68: e8bd4070 pop {r4, r5, r6, lr}
6c: e12fff1e bx lr
Of course, whether that has the same effect as the two separate pops depends on what the underlying bug in the system is - if it's something like the timing between the data fetches of the ldm and the instruction fetches of the jump itself, then this might be sufficiently equivalent; it could conceivably be something quite different, like a broken memory system truncating AHB bursts above a certain size, so it's the number of registers transferred in a single ldm that's the issue, but in that case I'd also expect to see problems with things like memcpy which aren't so easily fixed.

you can tell gcc to stop processing after it has generated the assembler. The you can edit the assembler files manually or by using sed. Then you pass the assembler file to as from binutils to assemble it into an object file.
$ cat test.c
#include <stdio.h>
int main(int argc, char *argv[])
{
printf ("hello world\n");
return 0;
}
$ gcc test.c -o test.s -S
cat test.s
.file "test.c"
.section .rodata
.LC0:
.string "hello world"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
movl $.LC0, %edi
call puts
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4"
.section .note.GNU-stack,"",#progbits
$ as test.s -o test.o

Related

Understanding a few of the 'helper' gnu-as directives

I have compiled a program main.c with about two lines of code to see what directives gcc / gas add to the unoptimized assembly file, using:
gcc -o main.s main.c -S
I can look up the concise description of each directive on the gas directive page, but was hoping someone could give a bit more context to some of these directives and what its practical usage is (for example, in gdb or the linker or wherever downstream). Here is the full assembly file with the items in question below:
.file "main.c"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $4, -8(%rbp)
movl $6, -4(%rbp)
movl -8(%rbp), %edx
movl -4(%rbp), %eax
addl %edx, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0"
.section .note.GNU-stack,"",#progbits
.file: it seems this is halfway-obsolete based on This statement may go away in future: it is only recognized to be compatible with old as programs.. But given that it is still there, where or how is this currently being used?
.ident: it seems like this gives the same thing as doing gcc --version. Is this used at all beyond giving helper information on the 'gcc' that was used to issue the command, or how is this used?
.section .note...: I have seen .section .text, .section .bss, .section .text, ...but I've never come across a .note, and doing a ctrl-f to search for note doesn't give anything on this page. What is this line doing with the three arguments? And the #progbits ?
.size: given that the directives take up no space, this is giving us the length of the first statement within main -- pushq %rbp minus the last statement ret, which is the length of the main function. But again, what usage is this? Also, it says on the as page that It is only permitted inside .def/.endef pairs., but this isn't inside those pairs, right?
.section .text.startup,"ax",#progbits -- what is text.startup, the ax looks like it means allocatable+executable, but what or where is the text.startup ?

if statement in assembly ouput of c code

i have this simple piece of code in c:
#include <stdio.h>
void test() {}
int main()
{
if (2 < 3) {
int zz = 10;
}
return 0;
}
when i see the assembly output of this code:
test():
pushq %rbp
movq %rsp, %rbp
nop
popq %rbp
ret
main:
pushq %rbp
movq %rsp, %rbp
movl $10, -4(%rbp) // space is created for zz on stack
movl $0, %eax
popq %rbp
ret
i got the assembly from here (default options)
I can't see where is the instruction for the conditional check?
You don't see it, because it isn't there. The compiler was able to perform analysis, and rather easily see that this branch will always be entered.
Instead of emitting a check that will do nothing but waste CPU cycles, it emits an easily optimized version of the code.
A C program is not a sequence of instructions for the CPU to perform. That's what the emitted machine code is. A C program is a description of the behavior your compiled program should have. A compiler is free to translate it in almost any way it wants, so long as you get that behavior.
It's known as "the as-if rule".
The interesting thing here is that gcc and clang optimize away the if() even at -O0, unlike some other compilers (ICC and MSVC).
gcc -O0 doesn't mean no optimization, it means no extra optimization beyond what's needed to compile at all. But gcc does have to transform through a couple internal representations of the function logic before emitting asm. (GIMPLE and Register Transfer Language). gcc doesn't have a special "dumb mode" where it slavishly transliterates every part of every C expression to asm.
Even a super-simple one-pass compiler like TCC does minor optimizations within an expression (or even a statement), like realizing that an always-true condition doesn't require branching.
gcc -O0 is the default, which you obviously used because the dead store to zz isn't optimized away.
gcc -O0 aims to compile quickly, and to give consistent debugging results.
Every C variable exists in memory, whether it's ever used or not.
Nothing is kept in registers across C statements (except variables declared register; -O0 is the only time that keyword does anything). So you can modify any C variable with a debugger while single-stepping. i.e. spill/reload everything between separate C statements. See also Why does clang produce inefficient asm with -O0 (for this simple floating point sum)? (This is why benchmarking for -O0 is nonsense: writing the same code with fewer larger expressions is faster only at -O0, not with real settings like -O3).
Other interesting consequences: constant-propagation doesn't work, see Why does integer division by -1 (negative one) result in FPE? for a case where gcc uses div for a variable set to a constant, vs. something simpler for a literal constant.
Every statement is compiled independently, so you can even jump to a different source line (within the same function) using GDB and get consistent results. (Unlike in optimized code where that would be likely to crash or give nonsense, and definitely not match the C abstract machine).
Given all those requirements for gcc -O0 behaviour, if (2 < 3) can still be optimized to zero asm instructions. The behaviour doesn't depend on the value of any variable, and it's a single statement. There's no way it can ever be not-taken, so the simplest way to compile it is no instructions: fall-through into the { body } of the if.
Note that gcc -O0's rules / restrictions go far beyond the C as-if rule that the machine-code for a function merely has to implement all externally-visible behaviour of the C source. gcc -O3 optimizes the whole function down to just
main: # with optimization
xor eax, eax
ret
because it doesn't care about keeping asm for every C statement.
Other compilers:
See all 4 of the major x86 compilers on Godbolt.
clang is similar to gcc, but with a dead store of 0 to another spot on the stack, as well as the 10 for zz. clang -O0 is often closer to a transliteration of C into asm, for example it will use div for x / 2 instead of a shift, while gcc uses a multiplicative inverse for division by a constant even at -O0. But in this case, clang also decides that no instructions are sufficient for an always-true condition.
ICC and MSVC both emit asm for the branch, but instead of the mov $2, %ecx / cmp $3, %ecx you might expect, they both actually do 0 != 1 for no apparent reason:
# ICC18
pushq %rbp #6.1
movq %rsp, %rbp #6.1
subq $16, %rsp #6.1
movl $0, %eax #7.5
cmpl $1, %eax #7.5
je ..B1.3 # Prob 100% #7.5
movl $10, -16(%rbp) #9.16
..B1.3: # Preds ..B1.2 ..B1.1
movl $0, %eax #11.12
leave #11.12
ret #11.12
MSVC uses the xor-zeroing peephole optimization even without optimization enabled.
It's slightly interesting to look at which local / peephole optimizations compilers do even at -O0, but it doesn't tell you anything fundamental about C language rules or your code, it just tells you about compiler internals and the tradeoffs the compiler devs chose between spending time looking for simple optimizations vs. compiling even faster in no-optimization mode.
The asm is never intended to faithfully represent the C source in any kind of way that would let a decompiler reconstruct it. Just to implement equivalent logic.
It's simple. It is not there. The compiler optimized it away.
Here is the assembly when compiling with gcc without optimization:
.file "k.c"
.text
.globl test
.type test, #function
test:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
nop
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size test, .-test
.globl main
.type main, #function
main:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $10, -4(%rbp)
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size main, .-main
.ident "GCC: (Debian 6.3.0-18) 6.3.0 20170516"
.section .note.GNU-stack,"",#progbits
and here it is with optimization:
.file "k.c"
.text
.p2align 4,,15
.globl test
.type test, #function
test:
.LFB11:
.cfi_startproc
rep ret
.cfi_endproc
.LFE11:
.size test, .-test
.section .text.startup,"ax",#progbits
.p2align 4,,15
.globl main
.type main, #function
main:
.LFB12:
.cfi_startproc
xorl %eax, %eax
ret
.cfi_endproc
.LFE12:
.size main, .-main
.ident "GCC: (Debian 6.3.0-18) 6.3.0 20170516"
.section .note.GNU-stack,"",#progbits
As you can see, not only the comparison is optimized away. Almost the whole main is optimized away since it does not produce anything visible. The variable zz is never used. The only observable thing your code does is returning 0.
2 is always less tan 3 so, as the compiler know the result of 2<3 is always true, there is no need for an if decision in assembler.
The optimization means to generate less time / less code.
if (2<3)
is allways true, therefore the Compiler emmits no opcode for it.
The condition if (2<3) is always true. So a decent compiler would detect this generate the code as if the condition doesn't exist. In fact, if you optimize it with -O3, godbolt.org generates just:
test():
rep ret
main:
xor eax, eax
ret
This is again valid because a compiler is allowed optimise and transform the code as long as the observable behaviour is preserved.

memcopying data off the stack in C

I was putting together a C riddle for a couple of my friends when a friend drew my attention to the fact that the following snippet (which happens to be part of the riddle I'd been writing) ran differently when compiled and run on OSX
#include <stdio.h>
#include <string.h>
int main()
{
int a = 10;
volatile int b = 20;
volatile int c = 30;
int data[3];
memcpy(&data, &a, sizeof(data));
printf("%d %d %d\n", data[0], data[1], data[2]);
}
What you'd expect the output to be is 10 20 30, which happens to be the case under Linux, but when the code is built under OSX you'd get 10 followed by two random numbers. After some debugging and looking at the compiler-generated assembly I came to the conclusion that this is due to how the stack is built. I am by no means an assembly expert, but the assembly code generated on Linux seems pretty straightforward to understand while the one generated on OSX threw me off a little. Perhaps I could use some help from here.
This is the code that was generated on Linux:
.file "code.c"
.section .text.unlikely,"ax",#progbits
.LCOLDB0:
.section .text.startup,"ax",#progbits
.LHOTB0:
.p2align 4,,15
.globl main
.type main, #function
main:
.LFB23:
.cfi_startproc
movl $10, -12(%rsp)
xorl %eax, %eax
movl $20, -8(%rsp)
movl $30, -4(%rsp)
ret
.cfi_endproc
.LFE23:
.size main, .-main
.section .text.unlikely
.LCOLDE0:
.section .text.startup
.LHOTE0:
.ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609"
.section .note.GNU-stack,"",#progbits
And this is the code that was generated on OSX:
.section __TEXT,__text,regular,pure_instructions
.macosx_version_min 10, 12
.globl _main
.p2align 4, 0x90
_main: ## #main
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp0:
.cfi_def_cfa_offset 16
Ltmp1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp2:
.cfi_def_cfa_register %rbp
subq $16, %rsp
movl $20, -8(%rbp)
movl $30, -4(%rbp)
leaq L_.str(%rip), %rdi
movl $10, %esi
xorl %eax, %eax
callq _printf
xorl %eax, %eax
addq $16, %rsp
popq %rbp
retq
.cfi_endproc
.section __TEXT,__cstring,cstring_literals
L_.str: ## #.str
.asciz "%d %d %d\n"
.subsections_via_symbols
I'm really only interested in two questions here.
Why is this happening?
Are there any get-arounds to this issue?
I know this is not a practical way to utilize the stack as I'm a professional C developer, which is really the only reason I found this problem interesting to invest some of my time into.
Accessing memory past the end of a declared variable is undefined behaviour - there is no guarantee as to what will happen when you try to do that. Because of how the compiler generated the assembly under Linux, you happened to get the 3 variables directly in a row on the stack, however that behaviour is just a coincidence - the compiler could legally add extra data in between the variables on the stack or really do anything - the result is not defined by the language standard. So in answer to your first question, it's happening because what you're doing is not part of the language by design. In answer to your second, there's no way to reliably get the same result from multiple compilers because the compilers are not programmed to reliably reproduce undefined behaviour.
undefined behavior. You don't expect to copy 10, 20 ,30. You hope not to seg-fault.
There is nothing to guarantee that a,b, and c are sequential memory addresses, which is your naive assumption. On Linux, the compiler happened to make them sequential. You can't even rely on gcc always doing that.
You already know that the behavior is undefined. A good reason for the behavior to be different on OS/X and Linux is these systems use a different compiler, that generates different code:
When you run gcc in Linux, you invoke the installed version the Gnu C compiler.
When you run gcc in your version of OS/X, you most likely invoke the installed version of clang.
Try gcc --version on both systems and amaze your friends.

GCC assembly code shows 32bit registers on 64bit machine

I am trying to learn how to use ptrace library for tracing all system calls and their arguments. I am stuck in getting the arguments passed to system call.
I went through many online resources and SO questions and figured out that on 64 bit machine the arguments are stored in registers rax(sys call number), rdi, rsi, rdx, r10, r8, r9
in the same order. Check this website .
Just to confirm this I wrote a simple C program as follows
#include<stdio.h>
#include<fcntl.h>
int main() {
printf("some print data");
open("/tmp/sprintf.c", O_RDWR);
}
and generated assembly code for this using gcc -S t.c but assembly code generated is as below
.file "t.c"
.section .rodata
.LC0:
.string "some print data"
.LC1:
.string "/tmp/sprintf.c"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $.LC0, %edi
movl $0, %eax
call printf
movl $2, %esi
movl $.LC1, %edi
movl $0, %eax
call open
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
.section .note.GNU-stack,"",#progbits
As you can see this code is storing parameters on esi and edi instead.
Why is happening?
Also please guide me on what is the best way to access these passed arguments from these registers/memory location from a C code? How can I figure out if the contents of register is the argument itself or is it a memory location where actual argument is stored?
Thanks!
this code is storing parameters on esi and edi
32-bit instructions are smaller, thus preferred when possible. See also Why do most x64 instructions zero the upper part of a 32 bit register.
How can I figure out if the contents of register is the argument itself or is it a memory location where actual argument is stored?
The AMD64 SystemV calling convention never implicitly replaces a function arg with a hidden pointer. Integer / pointer args in the C prototype always go in the arg-passing registers directly.
structs / unions passed by value go in one or more registers, or on the stack.
The full details are documented in the ABI. See more links in the x86 tag wiki. http://www.x86-64.org/documentation.html is down right now, so I linked the current revision on github.

Bootloader - Display String Runtime Error

I am going to write my first "hello world" bootloader program.I found an article on CodeProject website.Here is link of it.
http://www.codeproject.com/Articles/664165/Writing-a-boot-loader-in-Assembly-and-C-Part
Up-to assembly level programming it was going well, but when I wrote program using c,same as given in this article, I faced a runtime error.
Code written in my .c file is as below.
__asm__(".code16\n");
__asm__("jmpl $0x0000,$main\n");
void printstring(const char* pstr)
{
while(*pstr)
{
__asm__ __volatile__("int $0x10": :"a"(0x0e00|*pstr),"b"(0x0007));
++pstr;
}
}
void main()
{
printstring("Akatsuki9");
}
I created image file floppy.img and checking output using bochs.
It was displaying something like this
Booting from floppy...
S
It should be Akatsuki9. I don't know where did I mistake? Can any one help me to find why am I facing this runtime error?
Brief Answer: The problem is with gcc (in fact, this specific application of generated code) and not with the C program itself. It's hidden in the assembly code.
Long Answer: A longer (more elaborate) explanation with specific details of the problem:
(It would be helpful to have the assembly code. It can be obtained using the -S switch of gcc or use the one that I got from gcc; I've attached it at the end). If you don't already know about opcode-prefixing, c-parameter passing in assembly, etc. then have a look at the following background information section. Looking at the assembly source, it's evident that it's 32bit code. gcc with '.code16' produces 16bit code for 32bit-mode processor (using operand-size prefixes). When this same exact code is run in real (i.e. 16bit) mode, it is treated as 32bit code. This is not an issue (80386 and later processors can execute it as such, previous processors just ignore the operand-size prefix). The problem occurs because gcc calculates offsets based on 32bit-mode of (processor) operation, which is not true (by default) when executing boot-code.
Some background information (experienced assembly language programmers should skip this):
1. Operand-size prefix: In x86, prefix bytes (0x66, 0x67, etc.) are used to obtain variants of an instruction. 0x66 is the operand-size prefix to obtain instruction for non-default operand size; gas uses this technique to produce code for '.code16'. For example, in real (i.e. 16bit) mode, 89 D8 corresponds to movw %bx,%ax while 66 89 D8 corresponds to movl %ebx,%eax. This relationship gets reversed in 32bit mode.
2. parameter passing in C: Parameters are passed on stack and accessed through the EBP register.
3. Call instruction: Call is a branching operation with the next instruction's address saved on stack (for resuming). near Call saves only the IP (when in 16bit mode) or EIP ( when in 32bit mode). far Call saves the CS (code-segment register) along with IP/EIP.
4. Push operation: Saves the value on stack. The size of object is subtracted from ESP.
Exact problem
We start at the
movl %esp, %ebp in main: {{ %ebp is set equal to %esp }}
pushl $.LC0 subtracts 4 from Stack Pointer {{ .LC0 addresses the char* "Akatsuki9"; it is getting saved on stack (to be accessed by printstring function) }}
call printstring subtracts 2 from Stack Pointer (16bit Mode; IP is 2bytes)
pushl %ebp in printstring: {{ 4 is subtracted from %esp }}
movl %esp, %ebp {{ %ebp and %esp are currently at 2+4(=6) bytes from the char *pstr }}
pushl %ebx changes %esp but not %ebp
movl 8(%ebp), %edx {{ Accessing 'pstr' at %ebp+8 ??? }}
Accessing 'pstr' at %ebp+8 instead of %ebp+6 (gcc had calculated an offset of 8, assuming 32bit EIP); the program has just obtained an invalid pointer and it's going to cause problem when the program dereferences it later: movsbl (%edx), %eax.
Fix
As of now I don't know of a good fix for this that will work with gcc. For writing boot-sector code, a native 16bit code-generator, I think, is more effective (size-limit & other quirks as explained above). If you insist on using gcc which currently only generates code for 32bit mode, the fix would be to avoid passing function parameters. For more information, refer to the gcc and gas manuals. And please let me know if there is a workaround or some option that works with gcc.
EDIT
I have found a fix for the program to make it work for the desired purpose while still using gcc. Kinda hackish & clearly not-recommended. Why post then? Well, sort of proof of concept. Here it is: (just replace your printstring function with this one)
void printstring(const char* pstr)
{
const char *hackPtr = *(const char**)((char *)&pstr-2);
while(*hackPtr)
{
__asm__ __volatile__("int $0x10": :"a"(0x0e00|*hackPtr),"b"(0x0007));
++hackPtr;
}
}
I invite #Akatsuki and others (interested) to verify that it works. From my above answer and the added C-pointer arithmetic, you can see why it should.
My Assembly-Source file
.file "bootl.c"
#APP
.code16
jmpl $0x0000,$main
#NO_APP
.text
.globl printstring
.type printstring, #function
printstring:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
pushl %ebx
.cfi_offset 3, -12
movl 8(%ebp), %edx
movl $7, %ebx
.L2:
movsbl (%edx), %eax
testb %al, %al
je .L6
orb $14, %ah
#APP
# 8 "bootl.c" 1
int $0x10
# 0 "" 2
#NO_APP
incl %edx
jmp .L2
.L6:
popl %ebx
.cfi_restore 3
popl %ebp
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size printstring, .-printstring
.section .rodata.str1.1,"aMS",#progbits,1
.LC0:
.string "Akatsuki9"
.section .text.startup,"ax",#progbits
.globl main
.type main, #function
main:
.LFB1:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
pushl $.LC0
call printstring
popl %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE1:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
.section .note.GNU-stack,"",#progbits
I have the same problem, and found a solution that may work for you. It works on the emulators (I tested on bochs and qemu), but can't make it work on real hardware.
Solution
One thing is to use gcc-4.9.2, and to change the code generation to .code16gcc.
Thus, your code becomes:
__asm__(".code16gcc\n");
__asm__("jmpl $0x0000,$main\n");
void printstring(const char* pstr)
{
while(*pstr)
{
__asm__ __volatile__("int $0x10": :"a"(0x0e00|*pstr),"b"(0x0007));
++pstr;
}
}
void main()
{
printstring("Akatsuki9");
}
and to compile it use the -m16 flag on gcc, in my case I tried
gcc -c -m16 file.c
Note that you can change the architecture according to your needs, by setting -march. Or if you want to keep the flags of the tutorial
gcc -c -g -Os -march=i386 -ffreestanding -Wall -Werror -m16 file.c
tl;dr
Set .code16gcc instead of .code16, and use -m16 with gcc-4.9.2.

Resources