How are variables are located in memory? I have this code
int w=1;
int x=1;
int y=1;
int z=1;
int main(int argc, char** argv) {
printf("\n w %d",&w);
printf("\n x %d",&x);
printf("\n y %d",&y);
printf("\n z %d",&z);
return (EXIT_SUCCESS);
}
and it prints this
w 134520852
x 134520856
y 134520860
z 134520864
We can see that when other integer is declare and assigned, the address is moved four positions (bytes I suppose, it seems very logic). But if we don't assign the variables, like in the next code:
int w;
int x;
int y;
int z;
int main(int argc, char** argv) {
printf("\n w %d",&w);
printf("\n x %d",&x);
printf("\n y %d",&y);
printf("\n z %d",&z);
return (EXIT_SUCCESS);
}
it prints this
w 134520868
x 134520864
y 134520872
z 134520860
We can see there are four positions between addresses, but they are not in order. Why is this? How works the compiler in that case?
In case you want to know why I'm asking this, it is because I'm starting to study some security and I'm trying to understand some attacks, for instance, how integer overflow attacks work, and I've been playing with pointers in C to modify other variables by adding more positions than the size of the variable and things like that.
Your first example initialises variables, which generates different allocation code. By looking into the assembly file generated by gcc (gas) I get:
.globl _w
.data
.align 4
_w:
.long 1
.globl _x
.align 4
_x:
.long 1
.globl _y
.align 4
_y:
.long 1
.globl _z
.align 4
_z:
.long 1
And this basically dictates the memory addresses.
Your second example creates uninitialised variables, and as Jonathan said, those go into BSS. The assembler code is:
.comm _w, 4, 2
.comm _x, 4, 2
.comm _y, 4, 2
.comm _z, 4, 2
And that means you can't guarantee the sequence in which those variables will be located in memory.
The second set of numbers is also consecutive, just not ordered the same as in the source. I think the reason for this is simply that when you initialize the variables the compiler puts them in order because it maintains the order of initializations, in the second case you just get a random order.
In any case this depends on the compiler; I get the same pattern (ordered, 4 bytes apart) in both cases.
Related
Currently studying C. When I define, for example, a vector, such as:
float var1[2023] = {-53.3125}
What would the corresponding X86 Assembly translation look like? I'm looking for the exact portion of code where the variable is defined, where the ".type" and ".size" and alignment values are mentioned.
I've seen on the internet that when dealing with a floating-point number, the X86 Assembly conversion will simply be ".long". However, I'm not sure to what point that is correct.
One easy way to find out is to ask the compiler to show you:
// float.c
float var1[2023] = { -53.3125 };
then compile it:
$ gcc -S float.c
and then study the output:
.file "float.c"
.globl var1
.data
.align 32
.type var1, #object
.size var1, 8092
var1:
.long 3260366848
.zero 8088
.ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-39)"
.section .note.GNU-stack,"",#progbits
Note that this is just GCC's implementation; clang does it differently:
.file "float.c"
.type var1,#object # #var1
.data
.globl var1
.align 16
var1:
.long 3260366848 # float -5.331250e+01
.long 0 # float 0.000000e+00
.long 0 # float 0.000000e+00
// thousands of these
.size var1, 8092
.ident "clang version 3.4.2 (tags/RELEASE_34/dot2-final)"
.section ".note.GNU-stack","",#progbits
EDIT - To answer the comment below, the use of long simply lays down a specific bit pattern that encodes the compiler's idea of floating point format.
The value 3260366848 is the same as hex 0xC2554000, which is 11000010010101010100000000000000 in binary, and it's the binary value that the CPU cares about. If you care to, you can get out your IEEE floating point spec and decode this, there's the sign, that's the exponent, etc. but all the details of the floating point encoding were handled by the compiler, not the assembler.
I'm no kind of compiler expert, but decades ago I was tracking down a bug in a C compiler's floating point support, and though I don't remember the details, in the back of my mind it strike me as having the compiler do this would have been helpful by saving me from having to use a disassembler to find out what the bit pattern was actually encoded.
Surely others will weigh in here.
EDIT2 Bits are bits, and this little C program (which relies on sizeof int and sizeof float being the same size), demonstrates this:
// float2.c
#include <stdio.h>
#include <memory.h>
int main()
{
float f = -53.3125;
unsigned int i;
printf("sizeof int = %lu\n", sizeof(i));
printf("sizeof flt = %lu\n", sizeof(f));
memcpy(&i, &f, sizeof i); // copy float bits into an int
printf("float = %f\n", f);
printf("i = 0x%08x\n", i);
printf("i = %u\n", i);
return 0;
}
Running it shows that bits are bits:
sizeof int = 4
sizeof flt = 4
float = -53.312500
i = 0xc2554000
i = 3260366848 <-- there ya go
This is just a display notion for 32 bits depending on how you look at them.
Now to answer the question of how would you determine 3260366848 on your own from the floating point value, you'd need to get out your IEEE standard and draw out all the bits manually (recommend strong coffee), then read those 32 bits as an integer.
How do I get rid of alignment (.align 4 below) for all global variables by default with GCC, without having to specify __attribute__((aligned(1))) for each variable?
I know that what I ask for is a bad idea to apply universally, becuase on some architectures an alignment of 1 wouldn't work, because e.g. the CPU is not able to dereference an unaligned pointer. Bit in my case I'm writing an i386 bootloader, and unaligned pointers are fine (but slower) there.
Source code (a.c):
__attribute__((aligned(1))) int answer0 = 41;
int answer = 42;
Compiled with: gcc -m32 -Os -S a.c
Assembly output (a.s):
.file "a.c"
.globl answer
.data
.align 4
.type answer, #object
.size answer, 4
answer:
.long 42
.globl answer0
.type answer0, #object
.size answer0, 4
answer0:
.long 41
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
.section .note.GNU-stack,"",#progbits
The flag gcc -fpack-struct=1 changes the alignment of all struct members and structs to 1. For example, with that flag
struct x { char a; int b; };
struct y { int v : sizeof(char) + sizeof(int) == sizeof(struct x); };
struct z { int b; };
struct x x = { 1, 1 };
int i = 42;
struct z z = { 2 };
compiles to no alignment for variables x' andz', but it still has an .align 4 for the variable i (of type int). I need a solution which also makes int i = 42; unaligned, without having to specify something extra for each such variable.
IMO packing variables to save the space using the packed struct is the easiest and safest way.
example:
#include <stdio.h>
#include <stdint.h>
#define _packed __attribute__((packed))
_packed struct
{
uint8_t x1;
_packed int x2;
_packed uint8_t x3[2];
_packed int x4;
}byte_int;
int main(void) {
printf("%p %p %p %p\n", &byte_int.x1, &byte_int.x2, &byte_int.x3, &byte_int.x4);
printf("%u %u %u %u\n", (unsigned int)&byte_int.x1, (unsigned int)&byte_int.x2, (unsigned int)&byte_int.x3, (unsigned int)&byte_int.x4); // I know it is an UB just to show the op in dec - easier to spot the odd and the even addresses
return 0;
}
https://ideone.com/bY1soH
Most probably gcc doesn't have such a flag which can change the default alignment of global variables.
gcc -fpack-struct=1 can be a workaround, but only for global variables which happen to be of struct type.
Also post-processing the .s output of gcc and removing (some of) the .align lines could work as a workaround.
I have an assembly code (hello1.s) where global label A_Td is defined and I want to access all the long data values defined with global label A_Td from/inside C program.
.file "hello1.s"
.globl A_Td
.text
.align 64
A_Td:
.long 1353184337,1353184337
.long 1399144830,1399144830
.long 3282310938,3282310938
.long 2522752826,2522752826
.long 3412831035,3412831035
.long 4047871263,4047871263
.long 2874735276,2874735276
.long 2466505547,2466505547
As A_Td is defined in text section, so it is placed in code section and only one copy is loaded into memory.
Using yasm , I have generated hello1.o file
yasm -p gas -f elf32 hello1.s
Now, to access all the long data using global label A_Td , I have written following C code (test_glob.c) taking clue from here global label.
//test_glob.c
extern A_Td ;
int main()
{
long *p;
int i;
p=(long *)(&A_Td);
for(i=0;i<16;i++)
{
printf("p+%d %p %ld\n",i, p+i,*(p+i));
}
return 0;
}
Using following command I have compiled C program and then run the C code.
gcc hello1.o test_glob.c
./a.out
I am getting following output
p+0 0x8048400 1353184337
p+1 0x8048404 1353184337
p+2 0x8048408 1399144830
p+3 0x804840c 1399144830 -----> correct till this place
p+4 0x8048410 -1012656358 -----> incorrect value retrieved from this place
p+5 0x8048414 -1012656358
p+6 0x8048418 -1772214470
p+7 0x804841c -1772214470
p+8 0x8048420 -882136261
p+9 0x8048424 -882136261
p+10 0x8048428 -247096033
p+11 0x804842c -247096033
p+12 0x8048430 -1420232020
p+13 0x8048434 -1420232020
p+14 0x8048438 -1828461749
p+15 0x804843c -1828461749
ONLY first 4 long values are correctly accessed from C program. Why this is happening ?
What needs to be done inside C program to access the rest of data correctly ?
I am using Linux. Any help to resolve this issue or any link will be a great help. Thanks in advance.
How many bytes does "long" have in this system?
It seems to me that printf interprets the numbers as four byte signed integers, where the value 3282310938 has the hex value C3A4171A, which is above 7FFFFFFF (in decimal: 2147483647) which is the largest four byte positive signed number, and hence a negative value -1012656358.
I assume that the assembler just interprets these four byte numbers as unsigned.
If you would use %lu instead of %ld, printf would interpret the numbers as unsigned, and should show what you expected.
I have a HIGHLY performance critical section in my code where i need to minimize cpu load as much as i can. If i have a struct that has one instance, is there ANY difference in performance between defining variables in code by iteself like this:
int something;
int randomVariable;
or defining them in struct?
struct Test
{
int something;
int randomVariable;
}
because i want to use struct to make code look better
In my opinion the best way to know this , first write two different programs in C , with struct and without struct and then make them assembly file with using
gcc -S file.c
Since i dont know your code , i directly assigned values to them :
int main() {
int something;
int randomVariable;
something = 3;
randomVariable = 3;
return 0;}
and
main() {
struct Test
{
int something;
int randomVariable;
}test;
test.something = 3;
test.randomVariable = 3;
return 0;}
and i get assembly files on my Ubuntu-64bit , intel i5 machine
I saw that assembly files are nearly same
.file "test1.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 $3, -8(%rbp) **Second one(with struct) has value -16 instead -8**
movl $3, -4(%rbp) **Second one has value -12 instead of -4**
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4"
.section .note.GNU-stack,"",#progbits
So according to that results I can say that two implementation has not any significant difference about CPU load. Only difference between them second one is using very very little more memory than first one.
First, to be fair, because i want to use struct to make code look better is purely a style thing. What looks better to one person may not look better to another.
I am a fan of struct when there is a choice, for several reasons.
Speed/size efficiency:
Compare a struct over over two discrete int variables when data needed to be passed as a function argument.
Using:
int a;
int b;
Or
typedef struct {
int a;
int b;
}VAR;
VAR var;
The same data could be passed as separate pointers via function arguments (assuming 32 bit addressing):
int func1(int *a, int *b);//two 32 bit addresses passed
Or:
int func2(VAR *v);//one 32 bit address passed
The efficiency (of this type) goes up directly as number of variable goes up.
(efficiency gain if there were 100 ints?)
In the first example, you are passing two int *, while in the second, only one. Its a small difference, but it is a difference. The magnitude of the advantage is also dependent on addressing used. 32bit or 64bit.
Code maintenance and readability:
function prototypes, when used as application programming interface (API) should be stable. Using struct as arguments or as a return type support this interface stability.
For example: Given a requirement to calculate the changing velocity in Cartesian coordinates of x, y & z, of an object moving in a straight line with respect to time, you might design a function that would be called repeatedly with current values of velocityxyz and accelerationxyz and timems. The number of arguments required clearly suggest use of a struct. Struct is also suggested as the return type:
typedef struct {
double x;
double y;
double z;
}VEL; //velocity
typedef struct {
double x;
double y;
double z;
}ACC; //acceleration
typedef struct {
VEL vel;
ACC acc;
time_t ms;
}KIN; //kinematics
KIN * GetVelocity(KIN *newV);
If a new requirement for knowing Positionxyz was added to the project, all that would have to be added is a new member of the KIN struct:
typedef struct {
double x;
double y;
double z;
}POS; //position
...
typedef struct {
POS pos;
VEL vel;
ACC acc;
time_t ms;
}KIN; //kinematics
KIN * GetVelocity(KIN *newV);//prototype will continue to work
//without changing interface (argument list)
KIN * GetPosition(KIN *newV);//new prototype for position also supported
Can a C compiler ever optimize a loop by running it?
For example:
int num[] = {1, 2, 3, 4, 5}, i;
for(i = 0; i < sizeof(num)/sizeof(num[0]); i++) {
if(num[i] > 6) {
printf("Error in data\n");
exit(1);
}
}
Instead of running this each time the program is executed, can the compiler simply run this and optimize it away?
Let's have a look… (This really is the only way to tell.)
Fist, I've converted your snippet into something we can actually try to compile and run and saved it in a file named main.c.
#include <stdio.h>
static int
f()
{
const int num[] = {1, 2, 3, 4, 5};
int i;
for (i = 0; i < sizeof(num) / sizeof(num[0]); i++)
{
if (num[i] > 6)
{
printf("Error in data\n");
return 1;
}
}
return 0;
}
int
main()
{
return f();
}
Running gcc -S -O3 main.c produces the following assembly file (in main.s).
.file "main.c"
.section .text.unlikely,"ax",#progbits
.LCOLDB0:
.section .text.startup,"ax",#progbits
.LHOTB0:
.p2align 4,,15
.globl main
.type main, #function
main:
.LFB22:
.cfi_startproc
xorl %eax, %eax
ret
.cfi_endproc
.LFE22:
.size main, .-main
.section .text.unlikely
.LCOLDE0:
.section .text.startup
.LHOTE0:
.ident "GCC: (GNU) 5.1.0"
.section .note.GNU-stack,"",#progbits
Even if you don't know assembly, you'll notice that the string "Error in data\n" is not present in the file so, apparently, some kind of optimization must have taken place.
If we look closer at the machine instructions generated for the main function,
xorl %eax, %eax
ret
We can see that all it does is XOR'ing the EAX register with itself (which always results in zero) and writing that value into EAX. Then it returns again. The EAX register is used to hold the return value. As we can see, the f function was completely optimized away.
Yes. The C compiler unrolls loops automatically with options -O3 and -Otime.
You didn't specify the compiler, but using gcc with -O3 and taking the size calculation outside the for maybe it could do a little adjustment.
Compilers can do even better than that. Not only can compilers examine the effect of running code "forward", but the Standard even allows them to work code logic in reverse in situations involving potential Undefined Behavior. For example, given:
#include <stdio.h>
int main(void)
{
int ch = getchar();
int q;
if (ch == 'Z')
q=5;
printf("You typed %c and the magic value is %d", ch, q);
return 0;
}
a compiler would be entitled to assume that the program will never receive any input which would cause the printf to be reached without q having received a value; since the only input character which would cause q to receive a value would be 'Z', a compiler could thus legitimately replace the code with:
int main(void)
{
getchar();
printf("You typed Z and the magic value is 5");
}
If the user types Z, the behavior of the original program will be well-defined, and the behavior of the latter will match it. If the user types anything else, the original program will invoke Undefined Behavior and, as a consequence, the Standard will impose no requirements on what the compiler may do. A compiler will be entitled to do anything it likes, including producing the same result as would be produced by typing Z.