I try to understand things about stackpointer, basepointer .. how does it work .. and because most of the teaching material are not combined with a practical examples, I try to reproduce that: https://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames
Following very simple code by me:
#include <stdio.h>
int main()
{
function1(1, 2);
}
int function1(int a, int b)
{
int c = a + b;
return c;
}
I use WinDbg to execute the programm and set the breakpoint bm CallStackPractice!function1 and type g to hit the breakpoint and p to step into the function.
With ebp+8 we should get the first parameter. I did that in WinDbg:
0:000> ? poi(ebp+8)
Evaluate expression: 1 = 00000001
good. No we want our second parameter that should be ebp+12.
0:000> ? poi(ebp+12)
Evaluate expression: 270729434 = 102300da
We don't get 2 = 00000002. I opened the memory window in WinDbg and it shows me the correct value but why does my command not work?
Thank you!
UPDATE:
For better understanding the screenshot:
That's a common mistake. 12 means 0x12 by default.
If you want a decimal number 12, use 0n12 or 0xC or change the default number format using n 10 (I don't know anyone who does that, actually).
0:000> ? 12
Evaluate expression: 18 = 00000000`00000012
0:000> n 10
base is 10
0:000> ? 12
Evaluate expression: 12 = 00000000`0000000c
Back at base 16:
1:005:x86> n 16
base is 16
1:005:x86> ? poi(ebp+8)
Evaluate expression: 1 = 00000001
1:005:x86> ? poi(ebp+c)
Evaluate expression: 2 = 00000002
If you get weird errors like
1:005:x86> ?poi(ebp +c)
Memory access error at ')'
that's because you're still at base 10.
You might also want to take a look at the stack with dps like so:
1:005:x86> dps ebp-c L7
008ff60c cccccccc <-- magic number (4x INT 3 breakpoint)
008ff610 00000003
008ff614 cccccccc
008ff618 008ff6f4
008ff61c 00fb189a DebugESPEBP!main+0x2a [C:\...\DebugESPEBP.cpp # 13]
008ff620 00000001 <-- a
008ff624 00000002 <-- b
As you see, dps will give you the return address as a symbol with line number. And you'll see that the memory layout in debug mode contains magic numbers helpful for debugging
Related
I'm trying to code a very basic Assembler language in C.
Each instruction has 32 bits, the first 8 being the Opcode and the following 24 containing an immediate value (if the instruction comes with one. Else it's just zeros).
The Opcodes are defined as simple numbers. For example PUSHC is defined as 1.
Now I want to test if the Opcode and the immediate value are properly separable.
I wrote the following defintions:
#define SIGN_EXTEND(i) ((i) & 0x00800000 ? (i) | 0xFF000000 : (i)) // Handles negative Immediate Values (i)
#define IMMEDIATE(x) SIGN_EXTEND(x & 0x00FFFFFF) // Returns the Immediate Value of an instruction (x)
#define OPCODE(x) (x >> 24) // Returns the Opcode of an instruction (x)
#define OP(o) ((o) << 24) // An instruction with an Opcode (o)
#define OPI(o, i) (OP(o) | IMMEDIATE(i)) // An instruction with an Opcode (o) and an Immediate Value (i)
In a method void runProg(uint32_t prog[]) {...}, I pass an Array that contains the instructions for an Assembler program, in order, separated by commas, like such:
uint32_t progTest[] = {OPI(PUSHC, 3), OPI(PUSHC, 4}, OP(ADD), OP(HALT)};
runProg(progTest);
Here's what runProg does:
void runProg(uint32_t prog[]) {
int pc = -1; // the program counter
uint32_t instruction;
do {
pc++;
instruction = prog[pc];
printf("Command %d : 0x%08x -> Opcode [%d] Immediate [%d]\n",
pc, instruction, OPCODE(instruction), IMMEDIATE(instruction));
} while (prog[pc] != OP(HALT));
}
So it prints out the full command as a hexidecimal, followed by just the Opcode, followed by just the immediate value. This works for all instructions I have defined. The test program above gives this output:
Command 0 : 0x01000003 -> Opcode [1] Immediate [3]
Command 1 : 0x01000004 -> Opcode [1] Immediate [4]
Command 2 : 0x02000000 -> Opcode [2] Immediate [0]
Command 3 : 0x00000000 -> Opcode [0] Immediate [0]
Now here's the problem:
The command PUSHC only works with positive values.
Changing the immediate value of the first PUSHC call to -3 produces this result:
Command 0 : 0xfffffffd -> Opcode [255] Immediate [-3]
Command 1 : 0x01000004 -> Opcode [1] Immediate [4]
Command 2 : 0x02000000 -> Opcode [2] Immediate [0]
Command 3 : 0x00000000 -> Opcode [0] Immediate [0]
So as you can see, the immediate value is displayed correctly, however the command is missing the Opcode.
Changing the definition of IMMEDIATE(x)
from
#define IMMEDIATE(x) SIGN_EXTEND(x & 0x00FFFFFF)
to
#define IMMEDIATE(x) (SIGN_EXTEND(x) & 0x00FFFFFF)
produces the exact opposite result, where the Opcode is correctly separated, but the immediate value is wrong:
Command 0 : 0x01fffffd -> Opcode [1] Immediate [16777213]
Command 1 : 0x01000004 -> Opcode [1] Immediate [4]
Command 2 : 0x02000000 -> Opcode [2] Immediate [0]
Command 3 : 0x00000000 -> Opcode [0] Immediate [0]
Therefore, I am relatively sure that my definition of SIGN_EXTEND(i) is flawed. However, I can't seem to put my finger on it.
Any ideas on how to fix this are greatly appreciated!
0x01fffffd is correct; the 8-bit operation code field contains 0x01, and the 24-bit immediate field contains 0xfffffd, which is the 24-bit two’s complement encoding of −3. When encoding, there is no need for sign extension; the IMMEDIATE macro is passed a (presumably) 32-bit two’s complement value, and its job is merely to reduce it to 24 bits, not to extend it. So it merely needs to be #define IMMEDIATE(x) ((x) & 0xffffff). When you want to interpret the immediate field, as for printing, then you need to convert from 24 bits to 32. For that, you need a different macro, the way you have different macros to encode an operation code (OPI) and to decode/extract/interpret the operation code (OPCODE).
You can interpret the immediate field with this function:
static int InterpretImmediate(unsigned x)
{
// Extract the low 24 bits.
x &= (1u<<24) - 1;
/* Flip the sign bit. If the sign bit is 0, this
adds 2**23. If the sign bit is 1, this subtracts 2**23.
*/
x ^= 1u<<23;
/* Convert to int and subtract 2**23. If the sign bit started as 0, this
negates the 2**23 we added above. If it started as 1, this results in
a total subtraction of 2**24, which produces the two’s complement of a
24-bit encoding.
*/
return (int) x - (1u<<23);
}
I have a question to a behavior I detect with the gdb.
First I compiled this small program with the gcc on a 64bit machine:
#include <stdio.h>
#include <inttypes.h>
void fun (uint8_t *ar)
{
uint8_t i;
for(i = 0; i<4; i++)
{
printf("%i\n",*(&ar[0]+i));
}
}
int main (void)
{
uint8_t ar[4];
ar[0] = 0b11001100;
ar[1] = 0b10101010;
ar[2] = 0b01010110;
ar[3] = 0b00110011;
fun(ar);
return 0;
}
Then I look with the gdb to the memory of ar:
(gdb) p/t ar
$7 = {11001100, 10101010, 1010110, 110011}
(gdb) x ar
0x7fffffffe360: 00110011010101101010101011001100
(gdb) x 0x7fffffffe360
0x7fffffffe360: 00110011010101101010101011001100
(gdb) x 0x7fffffffe361
0x7fffffffe361: 11111111001100110101011010101010
(gdb) x 0x7fffffffe362
0x7fffffffe362: 01111111111111110011001101010110
(gdb) x 0x7fffffffe363
0x7fffffffe363: 00000000011111111111111100110011
I saw that the array of uint8_t was collect together to an 32 bit field. For the next addresses this will only push to the right.
&ar[0] -> {ar[3],ar[2],ar[1],ar[0]}
&ar[1] -> {xxxx,ar[3],ar[2],ar[1]}
&ar[2] -> {xxxx,xxxx,ar[3],ar[2]}
&ar[3] -> {xxxx,xxxx,xxxx,ar[3]}
It's a bit strange and I want to know: Why this will happen and can I rely on this behavior? Is this only typically for gcc or is this a handling standard?
In gdb, x just prints out whatever is in the memory location, regardless of its type in the C code. You're just getting some defaults (or previously used formats) for the width(4 bytes in your case) and format.
Do e.g. x/b ar to print the location as bytes. and do help x for more info.
If you print it as a anything other than a byte, endianess of your processor will determine how the memory is interpreted though.
Use p to take the type into account, as in p ar
It has to do with endianness:
In a x64, and every other little-endian machine, the data of value 0x12345678 is put into memory in the form 78 56 34 12, i. e. with the lowest significant byte first.
The debugger knows that and shows it to you in this way.
Expressed in hex, making your data easier to read, it looks this way:
Your memory is filled with
CC AA 56 33 FF 7F 00
which makes
the value at offset 0 3356AACC
the value at offset 1 FF3356AA
the value at offset 2 7FFF3356
the value at offset 3 007FFF33
Whilst being given a document teaching ARM assembly the document now tells me to load the CPRS into C and format the data into a friendly format, such as -
Flags: N Z IRQ FIQ
State: ARM
Mode: Supervisor
Now I've loaded the CPRS into a variable within my program, but I'm struggling to understand what format the CPRS is in, I've seen things using hex to reset flags and etc along which bytes are control, field, status and extension masks.
I put my CPRS into an int just to see what the data shows and I'm given 1610612752, I'm assuming I shouldn't be loading it into an int and something else in order for it to be much more clear.
Any hints pushing me to the right direction would be most appreciated.
From This wiki page, (http://www.heyrick.co.uk/armwiki/The_Status_register) we get the bit layout of the CPSR (and SPSR):
31 30 29 28 27 - 24 - 19 … 16 - 9 8 7 6 5 4 … 0
N Z C V Q - J - GE[3:0] - E A I F T M[4:0]
Declare some flags (or just compute these):
int armflag_N = (Cpsr>>31)&1;
int armflag_Z = (Cpsr>>30)&1;
int armflag_C = (Cpsr>>29)&1;
int armflag_V = (Cpsr>>28)&1;
int armflag_Q = (Cpsr>>27)&1;
int armflag_J = (Cpsr>>24)&1;
int armflag_GE = (Cpsr>>16)&7;
int armflag_E = (Cpsr>>9)&1;
int armflag_A = (Cpsr>>8)&1;
int armflag_I = (Cpsr>>7)&1;
int armflag_F = (Cpsr>>6)&1;
int armflag_T = (Cpsr>>5)&1;
int armflag_M = (Cpsr>>0)&15;
(The ">>" means to rightshift specified number of bits, and "&" is the bitwise and operator, so "(val>>num)&mask" means rightshift val num bits, and then extract the bits under the mask).
Now you have variables with flags, Here is how you could conditionally print a flag,
printf("Flags: ");
printf("%s ", armflag_N ? "N" : "-" );
...
I've made a 24 x 15 LED matrix using TLC5940s and shift registers, running on an Arduino Due.
First thing first, I want to print an ASCII char, eg. 'A' directly to the display.
So I stored a font array in PROGMEM, using a link I found :
PROGMEM prog_uchar font[][5] = {
{0x00,0x00,0x00,0x00,0x00}, // 0x20 32
{0x00,0x00,0x6f,0x00,0x00}, // ! 0x21 33
...
{0x08,0x14,0x22,0x41,0x00}, // < 0x3c 60
{0x14,0x14,0x14,0x14,0x14}, // = 0x3d 61
{0x00,0x41,0x22,0x14,0x08}, // > 0x3e 62
{0x02,0x01,0x51,0x09,0x06}, // ? 0x3f 63
etc.
Now, the weird part, is that everything almost works, but is shifted slightly.
For example, '>' gets morphed to this:
00000000 --> 00001000
01000001 --> 00000000
00100010 --> 01000001
00010100 --> 00100010
00001000 --> 00010100
So i think it is a pointer boundary issue. Maybe I've just been looking at it for too long, but I don't know!
Here is the relevant code, where I've hardcoded the values for '<'. I did a Serial.println, and it is showing the correct value for 'b'. x and y are 0 and 0, to place the character in the corner. The commented-out assignment of 'b' is what I usually do, instead of hardcoding. charWidth = 5 and charHeight = 7. setRainbowSinkValue(int led, int brightness) has worked forever, so it's not that.
unsigned char testgt[] = {0x00,0x41,0x22,0x14,0x08};
for (int iterations = 0; iterations < time; iterations++)
{
unsigned char indexOfWidth = 0;
unsigned char indexOfHeight = 0;
for (int col = x; col < x + charWidth; col++)
{
openCol(col);
Tlc.clear();
unsigned char b = testgt[indexOfWidth];//pgm_read_byte_near(font[ch] + indexOfWidth );
//Serial.println(b);
indexOfHeight = 0;
for (int ledNum = y; ledNum < y + charHeight; ledNum++)
{
if (b & (1 << indexOfHeight))
{
setRainbowSinkValue(ledNum, 100);
}
indexOfHeight++;
}
indexOfWidth++;
Tlc.update();
}
}
Can you see anything wrong? The most likely issue is the bit operations, but it makes sense...
b & 1...
b & 2...
b & 4...
b & 8...
b & 16...
b & 32...
b & 64...
b & 128...
Basically the value you extract from testgt[] goes into the wrong column on the display. The presented code looks fine. It's something in what you haven't shown. Perhaps, your circuitry is indexing the input differently from what you're expecting.
Ok I worked it out... There seems to be a slight timing difference between the speed of the 74hc595 and the TLC5940s, so what's happening is that there is residual flicker carried over to the next column because the TLC isn't cleared by the time the 74hc595 opens the new column. So I switched Tlc.clear() and openCol(col) and added a delay(5) in between, and that helps. Doesn't fix it entirely, but delay(15) hurts the eyes, and it's an acceptable compromise.
I have the following C code:
#define PRR_SCALE 255
...
uint8_t a = 3;
uint8_t b = 4;
uint8_t prr;
prr = (PRR_SCALE * a) / b;
printf("prr: %u\n", prr);
If I compile this (using an msp430 platform compiler, for an small embedded OS called contiki) the result is 0 while I expected 191.
(uint8_t is typedef'ed as an unsigned char)
If I change it to:
uint8_t a = 3;
uint8_t b = 4;
uint8_t c = 255;
uint8_t prr;
prr = (c * a) / b;
printf("prr: %u\n", prr);
it works out correctly and prints 191.
Compiling a simple version of this 'normally' using gcc on an Ubuntu box prints the correct value in both cases.
I am not exactly sure why this is. I could circumvent it by assigning the DEFINEd value to a variable beforehand, but I'd rather not do that.
Does anybody know why this is? Perhaps with a link to some more information about this?
The short answer: you compiler is buggy. (There is no problem with overflow, as others suggested.)
In both cases, the arithmetic is done in int, which is guaranteed to be at least 16 bits long. In the former snippet it's because 255 is an int, in the latter it's because of integral promotion.
As you noted, gcc handles this correctly.
255 is being processed as an integer literal and causes the entire expression to be int based rather than unsigned char based. The second case forces the type to be correct. Try changing your #define as follows:
#define PRR_SCALE ((uint8_t) 255)
If the compiler in question is the mspgcc, it should put out an assembler listing of the compiled program together with the binary/hex file. Other compilers may require additional compiler flags to do so. Or maybe even a separate disassembler run on the binary.
This is the place where to look for an explanation.
Due to compiler optimizations, the actual code presented to the processor might have not much similarity to the original C code (but normally does the same job).
Stepping through the few assembler instructions representing the faulty code should reveal the cause of the problem.
My guess is that the compiler somehow optimizes the whole calculation sice the defined constant is a known part at compile time.
255*x could be optimized to x<<8-x (which is faster and smaller)
Maybe something is going wrong with the optimized assembler code.
I took the time to compile both versions on my system. With active optimization, the mspgcc produces the following code:
#define PRR_SCALE 255
uint8_t a = 3;
uint8_t b = 4;
uint8_t prr;
prr = (PRR_SCALE * a) / b;
40ce: 3c 40 fd ff mov #-3, r12 ;#0xfffd
40d2: 2a 42 mov #4, r10 ;r2 As==10
40d4: b0 12 fa 6f call __divmodhi4 ;#0x6ffa
40d8: 0f 4c mov r12, r15 ;
printf("prr: %u\n", prr);
40da: 7f f3 and.b #-1, r15 ;r3 As==11
40dc: 0f 12 push r15 ;
40de: 30 12 c0 40 push #16576 ;#0x40c0
40e2: b0 12 9c 67 call printf ;#0x679c
40e6: 21 52 add #4, r1 ;r2 As==10
As we can see, the compiler directly calculates the result of 255*3 to -3 (0xfffd). And here is the problem. Somehow the 255 gets interpreted as -1 signed 8-bit instead of 255 unsigned 16 bit. Or it is parsed to 8 bit first and then sign-extended to 16 bit. or whatever.
A discussion on this topic has been started at the mspgcc mailing list already.
I'm not sure why the define doesn't work, but you might be running into rollovers with the uint8_t variables. 255 is the max value for uint8_t (2^8 - 1), so if you multiply that by 3, you're bound to run into some subtle rollover problems.
The compiler might be optimizing your code, and pre-calculating the result of your math expression and shoving the result in prr (since it fits, even though the intermediate value doesn't fit).
Check what happens if you break up your expression like this (this will not behave like what you want):
prr = c * a; // rollover!
prr = prr / b;
You may need to just use a larger datatype.
One difference I can think in case-1 is,
The PRR_SCALE literal value may go into ROM or code area. And there may be some difference in the MUL opecode for say,
case-1: [register], [rom]
case -2: [register], [register]
It may not make sense at all.