I am a reader of your great book CSAPP 2e. I've a question regarding chapter 3.6.6.
In this chapter the author used a function called cread to show that in some situation we should not use conditional moves.
function cread() is as follows:
int cread(int* xp) {
return (xp? *xp : 0);
}
The assembly code of this function is :
1 movl $0 , %eax Set 0 as return value
2 testl %edx , %edx Test xp
3 cmovne (%edx), %eax if !0, dereference xp to get return value
The author emphasized the problem is that the dereference of xp is invalid if xp is null. But as I see it, line 1 is for the condition that xp is a null pointer, and in line 3, if xp is null, (%edx) will not be copied to %eax, so this code has avoided the possibility of dereferencing a null pointer.
Additionally, when I looked this problem in CSAPP 3e, the assembly code of this function has changed as follows :
1 cread:
2 movq (%rdi), %rax
3 tests %rdi , %rdi
4 move $0 , %edx
5 cmove %rdx , %rax
6 ret
I can see the problem in the second assembly code that in line 2, if xp is null pointer then this dereference is an error. However, I cannot figure out if there's same error in the first piece of assembly code (actually I think this piece of code is correct).
My question is: Is my understanding correct, or is there really an error in the first piece of assembly code?
In the third instruction:
cmovne (%edx), %eax
it will first get the value of (%edx), then analyze the condition, and finally move (%edx) to %eax or not according to the condition.
So even if %edx=0, it will still access the value of (%edx), which will cause segmentation fault.
Related
I am writing a C program that calls an x86 Assembly function which adds two numbers. Below are the contents of my C program (CallAssemblyFromC.c):
#include <stdio.h>
#include <stdlib.h>
int addition(int a, int b);
int main(void) {
int sum = addition(3, 4);
printf("%d", sum);
return EXIT_SUCCESS;
}
Below is the code of the Assembly function (my idea is to code from scratch the stack frame prologue and epilogue, I have added comments to explain the logic of my code) (addition.s):
.text
# Here, we define a function addition
.global addition
addition:
# Prologue:
# Push the current EBP (base pointer) to the stack, so that we
# can reset the EBP to its original state after the function's
# execution
push %ebp
# Move the EBP (base pointer) to the current position of the ESP
# register
movl %esp, %ebp
# Read in the parameters of the addition function
# addition(a, b)
#
# Since we are pushing to the stack, we need to obtain the parameters
# in reverse order:
# EBP (return address) | EBP + 4 (return value) | EBP + 8 (b) | EBP + 4 (a)
#
# Utilize advanced indexing in order to obtain the parameters, and
# store them in the CPU's registers
movzbl 8(%ebp), %ebx
movzbl 12(%ebp), %ecx
# Clear the EAX register to store the sum
xorl %eax, %eax
# Add the values into the section of memory storing the return value
addl %ebx, %eax
addl %ecx, %eax
I am getting a segmentation fault error, which seems strange considering that I think I am allocating memory in accordance with the x86 calling conventions (e.x. allocating the correct memory sections to the function's parameters). Furthermore, if any of you have a solution, it would be greatly appreciated if you could provide some advice as to how to debug an Assembly program embedded with C (I have been using the GDB debugger but it simply points to the line of the C program where the segmentation fault happens instead of the line in the Assembly program).
Your function has no epilogue. You need to restore %ebp and pop the stack back to where it was, and then ret. If that's really missing from your code, then that explains your segfault: the CPU will go on executing whatever garbage happens to be after the end of your code in memory.
You clobber (i.e. overwrite) the %ebx register which is supposed to be callee-saved. (You mention following the x86 calling conventions, but you seem to have missed that detail.) That would be the cause of your next segfault, after you fixed the first one. If you use %ebx, you need to save and restore it, e.g. with push %ebx after your prologue and pop %ebx before your epilogue. But in this case it is better to rewrite your code so as not to use it at all; see below.
movzbl loads an 8-bit value from memory and zero-extends it into a 32-bit register. Here the parameters are int so they are already 32 bits, so plain movl is correct. As it stands your function would give incorrect results for any arguments which are negative or larger than 255.
You're using an unnecessary number of registers. You could move the first operand for the addition directly into %eax rather than putting it into %ebx and adding it to zero. And on x86 it is not necessary to get both operands into registers before adding; arithmetic instructions have a mem, reg form where one operand can be loaded directly from memory. With this approach we don't need any registers other than %eax itself, and in particular we don't have to worry about %ebx anymore.
I would write:
.text
# Here, we define a function addition
.global addition
addition:
# Prologue:
push %ebp
movl %esp, %ebp
# load first argument
movl 8(%ebp), %eax
# add second argument
addl 12(%ebp), %eax
# epilogue
movl %ebp, %esp # redundant since we haven't touched esp, but will be needed in more complex functions
pop %ebp
ret
In fact, you don't need a stack frame for this function at all, though I understand if you want to include it for educational value. But if you omit it, the function can be reduced to
.text
.global addition
addition:
movl 4(%esp), %eax
addl 8(%esp), %eax
ret
You are corrupting the stacke here:
movb %al, 4(%ebp)
To return the value, simply put it in eax. Also why do you need to clear eax? that's inefficient as you can load the first value directly into eax and then add to it.
Also EBX must be saved if you intend to use it, but you don't really need it anyway.
Consider the following code for producing a list of numbers from 0 to 9 along with values of 2 and -3 raised to the power of the corresponding number from the list:
#include <stdio.h>
int power(int m, int n);
main()
{
int i;
for (i = 0; i <= 10; ++i)
printf("%d %d %d\n", i, power(2, i), power(-3, i));
return 0;
}
int power(int base, int n)
{
int i, p;
p = 1;
for (i = 1; i <= n; ++i)
p = p * base;
// return statement purposefully omitted. //
}
Of course the program does not work properly without the return statement for the power function, however by running the written code I get the following output:
0 1 1
1 2 2
2 3 3
3 4 4
4 5 5
5 6 6
6 7 7
7 8 8
8 9 9
9 10 10
And I'm wondering where are the numbers in the second and third column of the output coming from? In lack of a valid return value of power, the control transfers back to the calling function, but why does it output these numbers?
As pointed out by #dyukha and #Daniel H, the value returned is "whatever is in your EAX register". Your function finishes on a for-loop, hence the last instruction realized before returning (ending the function) probably was a branching test, to check if i <= n (your loop condition). You can actually check on what variable is set to your EAX register by using your compiler to generate the assembly version of your code (option -S). You may try to follow what values are set into your register before the call to
popq %rbp
retq
at the end of your function.
On my computer, I tried with Apple LLVM version 9.0.0 (clang-900.0.39.2), which generate the following for my function:
movl %edi, -8(%rbp)
movl %esi, -12(%rbp)
movl $1, -20(%rbp)
movl $1, -16(%rbp)
LBB2_1: ## =>This Inner Loop Header: Depth=1
movl -12(%rbp), %eax
cmpl -16(%rbp), %eax
jl LBB2_4
## BB#2: ## in Loop: Header=BB2_1 Depth=1
movl -20(%rbp), %eax
imull -8(%rbp), %eax
movl %eax, -20(%rbp)
## BB#3: ## in Loop: Header=BB2_1 Depth=1
movl -16(%rbp), %eax
addl $1, %eax
movl %eax, -16(%rbp)
jmp LBB2_1
LBB2_4:
movl -4(%rbp), %eax
popq %rbp
retq
As you can see, I have 4 remarkable addresses: -8(%rbp), -12(%rbp), -16(%rbp) and -20(%rbp). Given the order of declaration in the C code, and the order of initialisation, -8(%rbp) is base, -12(%rbp) is n, -16(%rbp) is i and -20(%rbp) is p.
LBB2_1 is your loop condition. The instructions for the check are
* move value of n in %eax
* is the value of %eax lower then the value of i, store the result in %eax
* if %eax says that it was lower, go to label LBB2_4 else continue to next instruction
The three instructions after BB#2 are you actual multiplication. The three instructions after BB#3 are your increment of i, which is followed by an unconditional jump to your loop condition at label LBB2_1.
The ending of the power function is to take whatever is in memory address -4(%rbp), tu put it in %eax, and then leave the function (reset stack pointer, put value in %eax to the proper variable in the previous stack frame).
In the code produced by my compiler, I don't see the same result as you do, as I get every time the last two columns equal to 0 (-4(%rbp) is never set to anything). Except when adding a call to another function foo, taking two integers as parameters, having two local integer variables (to ensure that my new stack frame will be the same size as the power function one). This function actually set the address -4(%rbp). When calling my function right before entering the loop, I effectively find the value from -4(%rbp) as set in my function foo returned in my function power.
As a colleague just told me, playing with undefined behaviour is dangerous as your compiler is allowed to treat it any way it likes. It could be summoning a demon for what it's worth.
In definitive, or TL;DR, this undefined behaviour is handle in some way by the compiler. Whether some value is moved from one local variable, defined or not, or nothing special is moved to the register %eax is up to the compiler. Anyway, whatever was hanging in there, got returned when retq is called.
This question already has an answer here:
Pointers in Assembly
(1 answer)
Closed 9 years ago.
As an assignment, I must read the assembly code and write its high-level C program. The structure in this case is a switch statement, so for each case, the assembly code is translated to the case in C code. Below will only be one of the cases. If you can help me interpret this, it should give me a better understanding of the rest of the cases.
p1 is in %ebp+8
p2 is in %ebp+12
action is in %ebp+16
result is in %edx
...
.L13:
movl 8(%ebp), %eax # get p1
movl (%eax), %edx # result = *p1?
movl 12(%ebp), %ecx # get p2
movl (%ecx), %eax # p1 = *p2
movl 8(%ebp), %ecx # p2 = p1
movl %eax, (%ecx) # *p1 = *p2?
jmp .L19 #jump to default
...
.L19
movl %edx, %eax # set return value
Of course, the comments were added by me to try to make sense of it, except it leaves me more confused. Is this meant to be a swap? Probably not; the formatting would be different. What really happens in the 2nd and 6th lines? Why is %edx only changed once so early if it's the return value? Please answer with some guidelines to interpreting this code.
The above snippet is x86_32 assembly in the (IMO broken) AT&T syntax.
AT&T syntax attaches a size suffix to every operand.
movl means a 32 bit operand. (l for long)
movw means 16 bit operand (w for word)
movb means an 8 bit operand (b for byte)
The operands are reversed in order, so the destination is on the right and the source is on the left.
This is opposite to almost every other programming language.
Register names are prefixed by a % to distinguish them from variable names.
If a register is surrounded by brackets () that means that the memory address pointed to by the register is used, rather than the value inside the register itself.
This makes sense, because EBP is used as a pointer to a stackframe.
Stackframes are used to access parameters and local variables in functions.
Instead of writing: mov eax, dword ptr [ebp+8] (Intel syntax)
AT&T syntax lists it as: movl 8(%ebp), %eax (gas syntax)
Which means: put the contends of the memory address pointed to by (ebp + 8) into eax.
Here's the translation:
.L13: <<-- label used as a jump target.
movl 8(%ebp), %eax <<-- p1, stored at ebp+8 goes into EAX
movl (%eax), %edx <<-- p1 is a pointer, EDX = p1->next
movl 12(%ebp), %ecx <<-- p2, stored at ebp+12 goes in ECX
movl (%ecx), %eax <<-- p2 is (again) a pointer, EAX = p2->next
movl 8(%ebp), %ecx <<-- ECX = p1
movl %eax, (%ecx) <<-- p2->next = p1->next
jmp .L19 <<-- jump to exit
...
.L19
movl %edx, %eax <<-- EAX is always the return value
<<-- return p1->data.
In all of the many calling conventions on x86 the return value of a function is put into the EAX register. (or EAX:EDX if it's an INT64)
In prose: p1 and p2 are pointers to data, in this data pointers to pointers.
This code looks like it manipulates a linked list.
p2->next is set to p1->next.
Other than that the snippet looks incomplete because whatever was in p2->next to begin with is not worked on so there probably more code that you're not showing.
Apart from the confusing AT&T syntax it's really very simple code.
In C the code would look like:
(void *)p2->next = (void *)p1->next;
Note that the code is quite inefficient and no decent compiler (or human) would generate this code.
The following equivalent would make more sense:
mov eax,[ebp+8]
mov ecx,[ebp+12]
mov eax,[eax]
mov [ecx],eax
jmp done
More info on the difference between AT&T and Intel syntax can be found here: http://www.ibm.com/developerworks/linux/library/l-gas-nasm/index.html
This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 9 years ago.
#include<stdio.h>
#define CUBE(x) (x*x*x)
int main()
{
int a, b=3;
a = CUBE(++b);
printf("%d, %d\n", a, b);
return 0;
}
This code returns the value of a=150 and b=6. Please explain this.
I think when it executes the value of a will be calculated as a=4*5*6=120 but it isn't true according to the compiler , so please explain the logic....
There's no logic, it's undefined behavior because
++b * ++b * ++b;
modifies and reads b 3 times with no interleaving sequence points.
Bonus: You'll see another weird behavior if you try CUBE(1+2).
In addition to what Luchian Grigore said (which explains why you observe this weird behavior) you should notice that this macro is horrible: it can cause subtle and very difficult to track-down bugs, especially when called with a statement that has side-effects (like ++b) since this will cause the statement to execute multiple times.
You should learn three thing from this:
Never reference a macro argument more than once in a macro. While there are exceptions to this rule, you should prefer to think of it as absolute.
Try to avoid calling macros with statements that contain side-effects if possible.
Try to avoid function-like macros when possible. Use inline functions instead.
Its undefined behavior to change same variable more then once in a sequence. And because this reason you will get difference results with different compilers for your code.
By the chance I am also getting same result a = 150 and b = 6 with my compiler.
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
Your macro expression a = CUBE(++b); expanses as
a = ++b * ++b * ++b;
And b is change more then once before end of full expression..
But how my compiler convert this expression at low level (may be your compiler do similarly and you can try with same technique). for this I compiled the source C with -S option and I got an assembly code.
gcc x.c -S
you will get x.s file.
I am showing partial useful asm code (read comments)
Because you want to know how does 150 output, thats why I am adding my answer
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $3, -8(%rbp) // b = 3
addl $1, -8(%rbp) // b = 4
addl $1, -8(%rbp) // b = 5
movl -8(%rbp), %eax // eax = b
imull -8(%rbp), %eax // 5*5 = 25
addl $1, -8(%rbp) // 6 `b` become 6 and
imull -8(%rbp), %eax // 6 * 25 = 150
movl %eax, -4(%rbp) // 150 assign to `a` become 150
movl $.LC0, %eax // printf function stuff...
movl -8(%rbp), %edx
movl -4(%rbp), %ecx
movl %ecx, %esi
movq %rax, %rdi
On inspecting this assembly code I can understand it evaluate the expression like
a = 5 * 5 * 6 thus a becomes 150 and after three increments b becomes 6.
Although different compilers produce different result but I think, 150 cab only be evaluated this sequence for b=3 and your expression in 5*5*6
Wanting to see the output of the compiler (in assembly) for some C code, I wrote a simple program in C and generated its assembly file using gcc.
The code is this:
#include <stdio.h>
int main()
{
int i = 0;
if ( i == 0 )
{
printf("testing\n");
}
return 0;
}
The generated assembly for it is here (only the main function):
_main:
pushl %ebpz
movl %esp, %ebp
subl $24, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
call __alloca
call ___main
movl $0, -4(%ebp)
cmpl $0, -4(%ebp)
jne L2
movl $LC0, (%esp)
call _printf
L2:
movl $0, %eax
leave
ret
I am at an absolute loss to correlate the C code and assembly code. All that the code has to do is store 0 in a register and compare it with a constant 0 and take suitable action. But what is going on in the assembly?
Since main is special you can often get better results by doing this type of thing in another function (preferably in it's own file with no main). For example:
void foo(int x) {
if (x == 0) {
printf("testing\n");
}
}
would probably be much more clear as assembly. Doing this would also allow you to compile with optimizations and still observe the conditional behavior. If you were to compile your original program with any optimization level above 0 it would probably do away with the comparison since the compiler could go ahead and calculate the result of that. With this code part of the comparison is hidden from the compiler (in the parameter x) so the compiler can't do this optimization.
What the extra stuff actually is
_main:
pushl %ebpz
movl %esp, %ebp
subl $24, %esp
andl $-16, %esp
This is setting up a stack frame for the current function. In x86 a stack frame is the area between the stack pointer's value (SP, ESP, or RSP for 16, 32, or 64 bit) and the base pointer's value (BP, EBP, or RBP). This is supposedly where local variables live, but not really, and explicit stack frames are optional in most cases. The use of alloca and/or variable length arrays would require their use, though.
This particular stack frame construction is different than for non-main functions because it also makes sure that the stack is 16 byte aligned. The subtraction from ESP increases the stack size by more than enough to hold local variables and the andl effectively subtracts from 0 to 15 from it, making it 16 byte aligned. This alignment seems excessive except that it would force the stack to also start out cache aligned as well as word aligned.
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
call __alloca
call ___main
I don't know what all this does. alloca increases the stack frame size by altering the value of the stack pointer.
movl $0, -4(%ebp)
cmpl $0, -4(%ebp)
jne L2
movl $LC0, (%esp)
call _printf
L2:
movl $0, %eax
I think you know what this does. If not, the movl just befrore the call is moving the address of your string into the top location of the stack so that it may be retrived by printf. It must be passed on the stack so that printf can use it's address to infer the addresses of printf's other arguments (if any, which there aren't in this case).
leave
This instruction removes the stack frame talked about earlier. It is essentially movl %ebp, %esp followed by popl %ebp. There is also an enter instruction which can be used to construct stack frames, but gcc didn't use it. When stack frames aren't explicitly used, EBP may be used as a general puropose register and instead of leave the compiler would just add the stack frame size to the stack pointer, which would decrease the stack size by the frame size.
ret
I don't need to explain this.
When you compile with optimizations
I'm sure you will recompile all fo this with different optimization levels, so I will point out something that may happen that you will probably find odd. I have observed gcc replacing printf and fprintf with puts and fputs, respectively, when the format string did not contain any % and there were no additional parameters passed. This is because (for many reasons) it is much cheaper to call puts and fputs and in the end you still get what you wanted printed.
Don't worry about the preamble/postamble - the part you're interested in is:
movl $0, -4(%ebp)
cmpl $0, -4(%ebp)
jne L2
movl $LC0, (%esp)
call _printf
L2:
It should be pretty self-evident as to how this correlates with the original C code.
The first part is some initialization code, which does not make any sense in the case of your simple example. This code would be removed with an optimization flag.
The last part can be mapped to C code:
movl $0, -4(%ebp) // put 0 into variable i (located at -4(%ebp))
cmpl $0, -4(%ebp) // compare variable i with value 0
jne L2 // if they are not equal, skip to after the printf call
movl $LC0, (%esp) // put the address of "testing\n" at the top of the stack
call _printf // do call printf
L2:
movl $0, %eax // return 0 (calling convention: %eax has the return code)
Well, much of it is the overhead associated with the function. main() is just a function like any other, so it has to store the return address on the stack at the start, set up the return value at the end, etc.
I would recommend using GCC to generate mixed source code and assembler which will show you the assembler generated for each sourc eline.
If you want to see the C code together with the assembly it was converted to, use a command line like this:
gcc -c -g -Wa,-a,-ad [other GCC options] foo.c > foo.lst
See http://www.delorie.com/djgpp/v2faq/faq8_20.html
On linux, just use gcc. On Windows down load Cygwin http://www.cygwin.com/
Edit - see also this question Using GCC to produce readable assembly?
and http://oprofile.sourceforge.net/doc/opannotate.html
You need some knowledge about Assembly Language to understand assembly garneted by C compiler.
This tutorial might be helpful
See here more information. You can generate the assembly code with C comments for better understanding.
gcc -g -Wa,-adhls your_c_file.c > you_asm_file.s
This should help you a little.