This question already has answers here:
Why is there no "sub rsp" instruction in this function prologue and why are function parameters stored at negative rbp offsets?
(2 answers)
Why does the x86-64 GCC function prologue allocate less stack than the local variables?
(1 answer)
Closed 2 years ago.
Let's take the following example I have from a single function:
first_function:
pushq %rbp
movq %rsp, %rbp
movq $2, -8(%rbp)
movq $4, -16(%rbp)
...
pop %rbp
ret
If we look at the stack before the ..., it gives us:
>>> x/4g $rbp-16
0x7fffffffe410: 0x0000000000000004 0x0000000000000002
0x7fffffffe420: 0x0000000000000000 0x00000000004000bd
Or for me, an easier way to visualize it is:
+----------------+--------------------+---------------------------+
| 0x7fffffffe420 | 0x00000000004000bd | # function return address |
+----------------+--------------------+---------------------------+
| 0x7fffffffe418 | 0x0000000000000000 | # from push %rbp |
+----------------+--------------------+---------------------------+
| 0x7fffffffe410 | 0x0000000000000002 | # from mov $2, -8(%rbp) |
+----------------+--------------------+---------------------------+
| 0x7fffffffe408 | 0x0000000000000004 | # from mov $4, -16(%rbp) |
+----------------+--------------------+--------------------------
My question then is wouldn't a sub-function call (for example, if I called another function call in the ... section) possibly clobber all the two variables I've added above (2, and 4)?
Related
As part of a compiler project I have to write GNU assembler code for x86 to compare floating point values. I have tried to find resources on how to do this online and from what I understand it works like this:
Assuming the two values I want to compare are the only values on the floating point stack, then the fcomi instruction will compare the values and set the CPU-flags so that the je, jne, jl, ... instructions can be used.
I'm asking because this only works sometimes. For example:
.section .data
msg: .ascii "Hallo\n\0"
f1: .float 10.0
f2: .float 9.0
.globl main
.type main, #function
main:
flds f1
flds f2
fcomi
jg leb
pushl $msg
call printf
addl $4, %esp
leb:
pushl $0
call exit
will not print "Hallo" even though I think it should, and if you switch f1 and f2 it still won't which is a logical contradiction. je and jne however seem to work fine.
What am I doing wrong?
PS: does the fcomip pop only one value or does it pop both?
TL:DR: Use above / below conditions (like for unsigned integer) to test the result of compares.
For various historical reasons (mapping from FP status word to FLAGS via fcom / fstsw / sahf which fcomi (new in PPro) matches), FP compares set CF, not OF / SF. See also http://www.ray.masmcode.com/tutorial/fpuchap7.htm
Modern SSE/SSE2 scalar compares into FLAGS follow this as well, with [u]comiss / sd. (Unlike SIMD compares, which have a predicate as part of the instruction, as an immediate, since they only produce a single all-zeros / all-ones result for each element, not a set of FLAGS.)
This is all coming from Volume 2 of Intel 64 and IA-32 Architectures Software Developer's Manuals.
FCOMI sets only some of the flags that CMP does. Your code has %st(0) == 9 and %st(1) == 10. (Since it's a stack they're loaded onto), referring to the table on page 3-348 in Volume 2A you can see that this is the case "ST0 < ST(i)", so it will clear ZF and PF and set CF. Meanwhile on pg. 3-544 Vol. 2A you can read that JG means "Jump short if greater (ZF=0 and SF=OF)". In other words it's testing the sign, overflow and zero flags, but FCOMI doesn't set sign or overflow!
Depending on which conditions you wish to jump, you should look at the possible comparison results and decide when you want to jump.
+--------------------+---+---+---+
| Comparison results | Z | P | C |
+--------------------+---+---+---+
| ST0 > ST(i) | 0 | 0 | 0 |
| ST0 < ST(i) | 0 | 0 | 1 |
| ST0 = ST(i) | 1 | 0 | 0 |
| unordered | 1 | 1 | 1 | one or both operands were NaN.
+--------------------+---+---+---+
I've made this small table to make it easier to figure out:
+--------------+---+---+-----+------------------------------------+
| Test | Z | C | Jcc | Notes |
+--------------+---+---+-----+------------------------------------+
| ST0 < ST(i) | X | 1 | JB | ZF will never be set when CF = 1 |
| ST0 <= ST(i) | 1 | 1 | JBE | Either ZF or CF is ok |
| ST0 == ST(i) | 1 | X | JE | CF will never be set in this case |
| ST0 != ST(i) | 0 | X | JNE | |
| ST0 >= ST(i) | X | 0 | JAE | As long as CF is clear we are good |
| ST0 > ST(i) | 0 | 0 | JA | Both CF and ZF must be clear |
+--------------+---+---+-----+------------------------------------+
Legend: X: don't care, 0: clear, 1: set
In other words the condition codes match those for using unsigned comparisons. The same goes if you're using FMOVcc.
If either (or both) operand to fcomi is NaN, it sets ZF=1 PF=1 CF=1. (FP compares have 4 possible results: >, <, ==, or unordered). If you care what your code does with NaNs, you may need an extra jp or jnp. But not always: for example, ja is only true if CF=0 and ZF=0, so it will be not-taken in the unordered case. If you want the unordered case to take the same execution path as below or equal, then ja is all you need.
Here you should use JA if you want it to print (ie. if (!(f2 > f1)) { puts("hello"); }) and JBE if you don't (corresponds to if (!(f2 <= f1)) { puts("hello"); }). (Note this might be a little confusing due to the fact that we only print if we don't jump).
Regarding your second question: by default fcomi doesn't pop anything. You want its close cousin fcomip which pops %st0. You should always clear the fpu register stack after usage, so all in all your program ends up like this assuming you want the message printed:
.section .rodata
msg: .ascii "Hallo\n\0"
f1: .float 10.0
f2: .float 9.0
.globl main
.type main, #function
main:
flds f1
flds f2
fcomip
fstp %st(0) # to clear stack
ja leb # won't jump, jbe will
pushl $msg
call printf
addl $4, %esp
leb:
pushl $0
call exit
I'm having trouble understanding registers in x86 Assembly, I know that EAX is the full 32 bits, AX is the lower 16 bits, and then AH and AL the higher and lower 8 bits of AX, But I'm doing a question.
If AL=10 and AH=10 what is the value in AX?
My thinking on this is to convert 10 into binary (1010) and then take that as the higher and lower bits of AX (0000 1010 0000 1010) and then converting this to decimal (2570) am I anywhere close to the right answer here, or way off?
As suggested by Peter Cordes, I would imagine the data as hexadecimal values:
RR RR RR RR EE EE HH LL
| | || ||
| | || AL
| | AH |
| | |___|
| | AX |
| |_________|
| EAX |
|_____________________|
RAX
...where RAX is the 64-bit register which exists in x86-64.
So if you had AH = 0x12 and AL = 0x34, like this:
00 00 00 00 00 00 12 34
| | || ||
| | || AL
| | AH |
| | |___|
| | AX |
| |_________|
| EAX |
|_____________________|
RAX
...then you had AX = 0x1234 and EAX = 0x00001234 etc.
Note that, as shown in this chart, AH is the only "weird" register here which is not aligned with the lower bits. The others (AL, AX, EAX, RAX for 64-bit) are just different sizes but all aligned on the right. (For example, the two bytes marked EE EE in the chart don't have a register name on their own.)
Writing AL, AH, or AX merge into the full RAX, leaving other bytes unmodified for historical reasons. (Prefer a movzx eax, byte [mem] or movzx eax, word [mem] load if you don't specifically want this merging: Why doesn't GCC use partial registers?)
Writing EAX zero-extends into RAX. (Why do x86-64 instructions on 32-bit registers zero the upper part of the full 64-bit register?)
I have some questions dealing with reading assembly instruction. I know the basic instruction syntax, but it gets confusing when some of the register comes with some address in front of it, or the question uses any of the strange instruction. Is there any easy to understand set of reference to the assembly instructions?
For example, I have a question to read these instruction:
0x401050 <what>: push %ebp
0x401051 <what+1>: mov %esp,%ebp
0x401053 <what+3>: sub $0xc,%esp
0x401056 <what+6>: mov 0x8(%ebp),%eax
0x401059 <what+9>: add $0x4,%eax
0x40105c <what+12>: mov %eax,0xfffffffc(%ebp)
0x40105f <what+15>: mov 0x8(%ebp),%eax
0x401062 <what+18>: imul 0xc(%ebp),%eax
0x401066 <what+22>: mov %eax,0xfffffff8(%ebp)
0x401069 <what+25>: mov 0xc(%ebp),%edx
0x40106c <what+28>: mov 0x8(%ebp),%eax
0x40106f <what+31>: sub %edx,%eax
0x401071 <what+33>: mov %eax,0xfffffff4(%ebp)
0x401074 <what+36>: mov 0xfffffff8(%ebp),%eax
0x401077 <what+39>: add 0xfffffffc(%ebp),%eax
0x40107a <what+42>: add 0xfffffff4(%ebp),%eax
0x40107d <what+45>: leave
0x40107e <what+46>: ret
0x401089 <main>: push %ebp
0x40108a <main+1>: mov %esp,%ebp
0x40108c <main+3>: sub $0x18,%esp
0x40108f <main+6>: and $0xfffffff0,%esp
0x401092 <main+9>: mov $0x0,%eax
0x401097 <main+14>: mov %eax,0xfffffff0(%ebp)
0x40109a <main+17>: mov 0xfffffff0(%ebp),%eax
0x40109d <main+20>: call 0x401420 <_alloca>
0x4010a2 <main+25>: call 0x4014b0 <__main>
0x4010a7 <main+30>: mov 0xc(%ebp),%eax
0x4010aa <main+33>: add $0x4,%eax
0x4010ad <main+36>: mov (%eax),%eax
0x4010af <main+38>: mov %eax,(%esp)
0x4010b2 <main+41>: call 0x4014d0 <atoi>
0x4010b7 <main+46>: mov %eax,0xfffffffc(%ebp)
0x4010ba <main+49>: mov 0xc(%ebp),%eax
0x4010bd <main+52>: add $0x8,%eax
0x4010c0 <main+55>: mov (%eax),%eax
0x4010c2 <main+57>: mov %eax,(%esp)
0x4010c5 <main+60>: call 0x4014d0 <atoi>
0x4010ca <main+65>: mov %eax,0xfffffff8(%ebp)
0x4010cd <main+68>: mov 0xfffffff8(%ebp),%eax
0x4010d0 <main+71>: inc %eax
0x4010d1 <main+72>: mov %eax,0x4(%esp)
0x4010d5 <main+76>: mov 0xfffffffc(%ebp),%eax
0x4010d8 <main+79>: add $0x2,%eax
0x4010db <main+82>: mov %eax,(%esp)
0x4010de <main+85>: call 0x401050 <what>
0x4010e3 <main+90>: mov %eax,0xfffffff4(%ebp)
0x4010e6 <main+93>: mov 0xfffffff4(%ebp),%eax
0x4010e9 <main+96>: mov %eax,0x4(%esp)
0x4010ed <main+100>: movl $0x40107f,(%esp)
0x4010f4 <main+107>: call 0x4014c0 <printf>
0x4010f9 <main+112>: mov $0x0,%eax
0x4010fe <main+117>: leave
0x4010ff <main+118>: ret
The questions are:
This program is invoked from the command line as shown:
./program 5 7
The procedure named what is called from main, with the following argument(s):
1) 6, 8
2) 7, 8
3) 5, 7
4) 7, 5
The procedure named what is called from main, and returns to main with the value:
1) 11
2) 24
3) 42
4) 66
Could anyone guide me how the instructions in this example works? Any suggestion or help would be appreciated. Thanks.
You should try and loading that binary into IDA. IDA gives you a better view of the structure and its easier to understand what it is you are trying to ask (aside from reading instructions).
Edit: https://www.hex-rays.com/products/ida/
This is for binaries, if it fits your needs, there is a free version of this software on the above page as well. You can use the demo version to do your work as well. I have used IDA Pro (demo) for viewing and editing iOS App Binaries.
To the comments below, you are the worst thing about Stack Exchange - therefore this is the last time I try to help. Reddit it is.
it's me again. I am working on a tool can that disassemble/reassemble stripped binaries and now I am sucked in a (external) symbol reuse issue.
The test is on 32-bit Linux x86 platform.
Suppose I am working on a C++ program, in the GCC compiler produced assembly code, there exists some instructions like this:
call _ZNSt8ios_baseC2Ev
movl _ZTTSt14basic_ifstreamIcSt11char_traitsIcEE+4, %ebx
movb $0, 312(%esp)
movl _ZTTSt14basic_ifstreamIcSt11char_traitsIcEE+8, %ecx
....
Please pay special attention to symbol _ZTTSt14basic_ifstreamIcSt11char_traitsIcEE.
After the compilation, suppose I get an unstripped binary, and i checked this symbol like this:
readelf -s a.out | grep "_ZTTSt14basic"
69: 080a7390 16 OBJECT WEAK DEFAULT 27 _ZTTSt14basic_ifstreamIcS#GLIBCXX_3.4 (3)
72: 080a7220 16 OBJECT WEAK DEFAULT 27 _ZTTSt14basic_ofstreamIcS#GLIBCXX_3.4 (3)
705: 080a7220 16 OBJECT WEAK DEFAULT 27 _ZTTSt14basic_ofstreamIcS
1033: 080a7390 16 OBJECT WEAK DEFAULT 27 _ZTTSt14basic_ifstreamIcS
See, this is my first question, why the name of symbol _ZTTSt14basic_ifstreamIcSt11char_traitsIcEE modified to _ZTTSt14basic_ifstreamIcS and _ZTTSt14basic_ifstreamIcS#GLIBCXX_3.4 (3) ?
What is _ZTTSt14basic_ifstreamIcS#GLIBCXX_3.4 (3) though?
Then I stripped the binary like this:
strip a.out
readelf -s a.out | grep "_ZTTSt14basic"
69: 080a7390 16 OBJECT WEAK DEFAULT 27 _ZTTSt14basic_ifstreamIcS#GLIBCXX_3.4 (3)
72: 080a7220 16 OBJECT WEAK DEFAULT 27 _ZTTSt14basic_ofstreamIcS#GLIBCXX_3.4 (3)
Then after I disassemble the binary, and the corresponding disassembled assembly instructions are :
8063ee7: e8 84 54 fe ff call 8049370 <_ZNSt8ios_baseC2Ev#plt>
8063eec: 8b 1d 94 73 0a 08 mov 0x80a7394,%ebx
8063ef2: c6 84 24 38 01 00 00 movb $0x0,0x138(%esp)
8063ef9: 00
8063efa: 8b 0d 98 73 0a 08 mov 0x80a7398,%ecx
At this point we can figure out that 0x80a7394 equals to _ZTTSt14basic_ifstreamIcSt11char_traitsIcEE+4.
In order to reuse these instructions, I modified the code:
call _ZNSt8ios_baseC2Ev
mov _ZTTSt14basic_ifstreamIcS+4,%ebx
movb $0x0,0x138(%esp)
mov _ZTTSt14basic_ifstreamIcS+8,%ecx
And did some update like these (please see this question for reference):
echo ""_ZTTSt14basic_ifstreamIcS#GLIBCXX_3.4 (3)" = 0x080a7390;" > symbolfile
g++ -Wl,--just-symbols=symbolfile final.s
readelf -s a.out | grep "_ZTTSt14basic"
3001: 080a7390 0 NOTYPE LOCAL DEFAULT 27 _ZTTSt14basic_ifstreamIcS
8412: 080a7390 0 NOTYPE GLOBAL DEFAULT ABS _ZTTSt14basic_ifstreamIcS
I debugged the newly produced binary, and to my surprise, in the newly produced binary, symbol _ZTTSt14basic_ifstreamIcS does not get any value after the function call of _ZNSt8ios_baseC2Ev, while in the original binary, after the function call, _ZTTSt14basic_ifstreamIcS do get some memory address referring to library section. Which means:
call _ZNSt8ios_baseC2Ev
mov _ZTTSt14basic_ifstreamIcS+4,%ebx <--- %ebx gets zero!
movb $0x0,0x138(%esp)
mov _ZTTSt14basic_ifstreamIcS+8,%ecx <--- %ecx gets zero!
I must state that in these lines of the original binary, registers %ebx and %ecx both gets some addresses referring to the libc section.
This is my second question, why does symbol _ZTTSt14basic_ifstreamIcS didn't get any value after function call _ZNSt8ios_baseC2Ev? I also tried with symbol name _ZTTSt14basic_ifstreamIcSt11char_traitsIcEE. But that does not work also.
Am I clear enough? Could anyone save my ass? thank you!
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 8 years ago.
Improve this question
Determine the value of each variable after calculation is performed. All variables have value 5 before execution.
A1/=++B1/--C1
A2+=++B2%C2--
please tell me how this work
Variables:
int A1 = 5;
int B1 = 5;
int C1 = 5;
int A2 = 5;
int B2 = 5;
int C2 = 5;
Your code:
A1 /= ++B1 / --C1;
A2 += ++B2 % C2--;
Will probably compile into something similar too:
++B1;
--C1;
A1 /= B1 / C1;
++B2;
A2 += B2 % C2;
C2--;
You can output the ASM using your compiler, with GCC its the -S flag. Here is the ASM output with GCC on my computer (I added the comments):
movl $5, -20(%rbp) // A1 = 5
movl $5, -24(%rbp) // B1 = 5
movl $5, -28(%rbp) // C1 = 5
movl $5, -32(%rbp) // A2 = 5
movl $5, -36(%rbp) // B2 = 5
movl $5, -40(%rbp) // C2 = 5
Then for the first one calculation, this is performed (comments simplified for easier understanding):
addl $1, -24(%rbp) // ++B1
subl $1, -28(%rbp) // --C1
movl -24(%rbp), %eax //
cltd
idivl -28(%rbp) // divide B1 by C1
movl %eax, %esi //
movl -20(%rbp), %eax //
cltd
idivl %esi // divide A1 by the previous
movl %eax, -20(%rbp)
By the C Operator Precedence Table: http://www.difranco.net/compsci/C_Operator_Precedence_Table.htm
For 1:
A1 /= ++B1 / --C1
C1 will first be decremented by 1 to 4
B1 will then be incremented by 1 to 6
B1 (6) will be divided by C1 (4), result of which will be 1
A1 will be assigned with the result of the division A1 (5) and 1, which is 5
Results for each will be 5, 6 and 4 for A1, B1 and C1, respectively.
For 2:
A2 += ++B2 % C2--
C2 will first be marked to get decremented close to the end of the statement, remains 5 for now
B2 will then be incremented by 1 to 6
The remainder from the division B2 (6) by C2 (5) will get calculated, which is 1
A2 will be assigned with the result of the addition of A2 (5) and 1, which is 6
C2 will be decremented by 1 to 4
Results for each will be 6, 6 and 4 for A2, B2 and C2, respectively.
Pardon me if I have made any mistakes, you can always check these with your compiler.