What are the four execution steps before entering main? [duplicate] - c

This question already has answers here:
Function Prologue and Epilogue in C
(4 answers)
Closed 3 years ago.
Take the following 5-line file I have:
#include <stdio.h>
int main() {
printf("Hello");
return 0;
}
It corresponds to the following assembly:
`main:
0x100000f60 <+0>: pushq %rbp
0x100000f61 <+1>: movq %rsp, %rbp
0x100000f64 <+4>: subq $0x10, %rsp
0x100000f68 <+8>: movl $0x0, -0x4(%rbp)
-> 0x100000f6f <+15>: leaq 0x34(%rip), %rdi ; "Hello"
We can notice the first line in main which prints "Hello" corresponds to the fifth instruction. What are the four preceding instructions: what do they do?

0x100000f60 <+0>: pushq %rbp
Push the caller's base pointer.
0x100000f61 <+1>: movq %rsp, %rbp
Copy the stack pointer into the base pointer (set up this function's stack frame)
0x100000f64 <+4>: subq $0x10, %rsp
Reserve stack space (presumably for the return value - you probably didn't compile this program with any optimizations enabled)
0x100000f68 <+8>: movl $0x0, -0x4(%rbp)
Put the return value (zero) on the stack.
-> 0x100000f6f <+15>: leaq 0x34(%rip), %rdi ; "Hello"
Load a pointer to the "Hello" string literal into rdi register.

Related

Initializing an array in C/asm [duplicate]

This question already has answers here:
how does array[100] = {0} set the entire array to 0?
(4 answers)
Why is there no "sub rsp" instruction in this function prologue and why are function parameters stored at negative rbp offsets?
(2 answers)
Compiler using local variables without adjusting RSP
(1 answer)
Closed 2 years ago.
The following C function:
int main(void) {
char name[10] = "H";
}
Produces the following (unoptimized) assembly in Compiler Explorer:
main:
pushq %rbp
movq %rsp, %rbp
movq $72, -10(%rbp)
movw $0, -2(%rbp) <--------- ??
movl $0, %eax
popq %rbp
ret
What does the line above do? I would think we would want to null terminal the string by adding a $0 but I don't undertand why it's being added at -2. If helpful, here is a screenshot:

Comparison of godbolt assembly of basic C program [duplicate]

This question already has answers here:
Why does clang produce inefficient asm with -O0 (for this simple floating point sum)?
(1 answer)
How many bytes does the push instruction push onto the stack when I don't specify the operand size?
(2 answers)
Does each PUSH instruction push a multiple of 8 bytes on x64?
(2 answers)
What's the difference between 'push' and 'pushq' in at&t assembly
(1 answer)
How to determine the appropriate MOV instruction suffix based on the operands?
(1 answer)
Closed 2 years ago.
I've written the following basic C program:
int main() {
char a = 1;
char b = 5;
return a + b;
}
And it compiles in godbolt as:
main:
pushq %rbp
movq %rsp, %rbp
movb $1, -1(%rbp)
movb $5, -2(%rbp)
movsbl -1(%rbp), %edx
movsbl -2(%rbp), %eax
addl %edx, %eax
popq %rbp
ret
I have a few questions about the compiled asm:
Is movb used for 1byte (char), movw for 2byte (short), movl for 4byte (int), and movq for 8byte (int) integers? What then is just mov used for, without an extension?
Why is an offset used for movb $1 -1(%rbp), movb $5 -2(%rbp)? Why aren't the two numbers just moved into two different registers? For example, there's an addl %edx, %eax later on...why aren't the two numbers just moved into those two registers?
Why is movsbl used here? Why aren't the numbers just moved directly into the registers?
Is pushq / popq pushing/popping an 8byte pointer onto the stack? If so, what's the point of the movq %rsp, %rbp?

An assembly code in book CSAPP [duplicate]

This question already has answers here:
Why does the x86-64 / AMD64 System V ABI mandate a 16 byte stack alignment?
(1 answer)
What does it mean to align the stack?
(6 answers)
Closed 4 years ago.
In the book CSAPP, 3.7.5 Local Storage in Registers, there is a calling function:
long P(long x, long y)
{
long u = Q(y);
long v = Q(x);
return u + v;
}
and the Generated assembly code for the calling function is:
P:
pushq %rbp
pushq %rbx
subq $8, %rsp Align stack frame
movq %rdi, %rbp
movq %rsi, %rdi
call Q
movq %rax, %rbx
movq %rbp, %rdi
call Q
addq %rbx, %rax
addq $8, %rsp
popq %rbx
popq %rbp
ret
I can't understand Line 3 subq $8, %rsp. The book says it is used to align stack frame. Why the machine align stack frame here?

Why does a C compiler generate NOPs after a RET instruction? [duplicate]

This question already has answers here:
Why does GCC pad functions with NOPs?
(3 answers)
Closed 7 years ago.
On OSX 64bit, compiling a dummy C program like that:
#include <stdio.h>
void foo1() {
}
void foo2() {
}
int main() {
printf("Helloooo!\n");
foo1();
foo2();
return 0;
}
Produces the following ASM code (obtained disassembling the binary with otool):
(__TEXT,__text) section
_foo1:
0000000100000f10 55 pushq %rbp
0000000100000f11 4889e5 movq %rsp, %rbp
0000000100000f14 897dfc movl %edi, -0x4(%rbp)
0000000100000f17 5d popq %rbp
0000000100000f18 c3 retq
0000000100000f19 0f1f8000000000 nopl (%rax)
_foo2:
0000000100000f20 55 pushq %rbp
0000000100000f21 4889e5 movq %rsp, %rbp
0000000100000f24 5d popq %rbp
0000000100000f25 c3 retq
0000000100000f26 662e0f1f840000000000 nopw %cs:(%rax,%rax)
_main:
0000000100000f30 55 pushq %rbp
0000000100000f31 4889e5 movq %rsp, %rbp
0000000100000f34 4883ec10 subq $0x10, %rsp
0000000100000f38 488d3d4b000000 leaq 0x4b(%rip), %rdi ## literal pool for: "Helloooo!\n"
0000000100000f3f c745fc00000000 movl $0x0, -0x4(%rbp)
0000000100000f46 b000 movb $0x0, %al
0000000100000f48 e81b000000 callq 0x100000f68 ## symbol stub for: _printf
0000000100000f4d bf06000000 movl $0x6, %edi
0000000100000f52 8945f8 movl %eax, -0x8(%rbp)
0000000100000f55 e8b6ffffff callq _foo1
0000000100000f5a e8c1ffffff callq _foo2
0000000100000f5f 31c0 xorl %eax, %eax
0000000100000f61 4883c410 addq $0x10, %rsp
0000000100000f65 5d popq %rbp
0000000100000f66 c3 retq
What are the "nop" instructions found right after the "ret" on functions foo1() and foo2()? They are, of course, never executed since the "ret" instructions return from the function call. Is that any kind of padding or it has a different meaning?
From the Assembly language for x86 processors, Kip R. Irvine
The safest (and the most useless) instruction you can write is called NOP (no operation). It takes up 1 byte of program storage and doesn’t do any work. It is sometimes used by compilers and assemblers to align code to even-address boundaries
00000000 66 8B C3 mov ax,bx
00000003 90 nop ; align next instruction
00000004 8B D1 mov edx,ecx
What are the "nop" instructions found right after the "ret" on functions foo1() and foo2()?
The nop is a no-operation instruction (do nothing), from the linked Wikipedia page (emphasis mine)
A NOP is most commonly used for timing purposes, to force memory alignment, to prevent hazards, to occupy a branch delay slot, to render void an existing instruction such as a jump, or as a place-holder to be replaced by active instructions later on in program development (or to replace removed instructions when refactoring would be problematic or time-consuming).
nop is short for No Operation. The nop instructions in this case are providing execution code alignment. Notice that labels are on 16 byte boundaries. On OSX, the linker (ld) should have a -segalign option that will affect this behavior.

Why does LLVM add two extra instructions for the same program?

I am compiling this C program and comparing the generated assembly code:
int main(){ return 0; }
GCC gives this main function (cc hello.c -S):
_main:
LFB2:
pushq %rbp
LCFI0:
movq %rsp, %rbp
LCFI1:
movl $0, %eax
leave
ret
LLVM gives this main function (clang hello.c -S):
_main:
Leh_func_begin0:
pushq %rbp
Ltmp0:
movq %rsp, %rbp
Ltmp1:
movl $0, %eax
movl $0, -4(%rbp)
popq %rbp
ret
Leh_func_end0:
What are movl $0, -4(%rbp) and popq %rbp needed for? Moving something on the stack and popping it directly afterwards seems useless to me.
The movl $0, -4(%rbp) instruction is dead, because this is unoptimized code. Try passing in -O to both compilers to see what changes.
Actually, they're comparable. Leave is a high level instruction:
From the Intel manual:
16-bit: C9 LEAVE A Valid Valid Set SP to BP, then pop BP.
32-bit: C9 LEAVE A N.E. Valid Set ESP to EBP, then pop EBP.
64-bit: C9 LEAVE A Valid N.E. Set RSP to RBP, then pop RBP.
basically, leave is equivalent to
movq %rbp, %rsp
popq %rbp
It looks like LLVM is using a traditional function prolog/epilog, whereas GCC is taking advantage of the fact that the entry point doesn't need to clean up

Resources