I've written some code (main in c, subprogram in assembly x86) to calculate all the binomial coefficients recursively and print out all the binomial coefficients with n=10, restricted by m<=n.
So basically I'm trying to output a pascals triangle for n=10. (without the whole format of a triangle)
My problem is that I'm getting a segfault on compile and I'm having trouble figuring out how to print the individual values generated by the recursive function.
Segmentation fault (core dumped)
Here's the main program:
#include <stdio.h>
unsigned int result,m,n,i;
unsigned int binom(int,int);
int main(){
n=10;
for (i=0; i<n+1;i++){
printf("i=%d | %d \n", i, binom(n,i) );
}
return;
}
And the recursive sub program:
.text
.globl binom
binom:
mov $0x00, %edx #for difference calculation
cmp %edi, %esi #m=n?
je equalorzero #jump to equalorzero for returning of value 1
cmp $0x00, %esi #m=0?
je equalorzero
cmp $0x01, %esi #m=1?
mov %esi,%edx
sub %edi, %edx
cmp $0x01, %edx # n-m = 1 ?
je oneoronedifference
jmp otherwise
equalorzero:
add $1, %eax #return 1
ret
oneoronedifference:
add %edi, %eax #return n
ret
otherwise:
sub $1, %edi #binom(n-1,m)
call binom
sub $1, %esi #binom(n-1,m-1)
call binom
This is what gcc is giving me
./runtimes
i=0 | 12
Segmentation fault (core dumped)
The two major issues with your assembly code are: 1) you niether add nor return the sum of the two recursive calls; 2) you don't save your locals on the stack so they are wiped out by the recursive calls -- you're using the wrong values once you return from the calls. Here's my rework of your code, some of the changes are due to my writing this under OSX:
The recursive sub program:
.text
.globl _binom
_binom:
pushq %rbp # allocate space on stack for locals
movq %rsp, %rbp
subq $24, %rsp
cmpl %edi, %esi # m == n ?
je equalorzero # jump to equalorzero for returning of value 1
cmpl $0, %esi # m == 0 ?
je equalorzero
movl %esi, %edx
subl %edi, %edx
cmpl $1, %edx # n - m == 1 ?
je oneoronedifference
subl $1, %edi # binom(n - 1, m)
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
callq _binom
movl %eax, -12(%rbp) # save result to stack
movl -4(%rbp), %edi
movl -8(%rbp), %esi
subl $1, %esi # binom(n - 1, m - 1)
callq _binom
addl -12(%rbp), %eax # add results of the two recursive calls
addq $24, %rsp # release locals space on stack
popq %rbp
retq
equalorzero:
movl $1, %eax # return 1
addq $24, %rsp # release locals space on stack
popq %rbp
retq
oneoronedifference:
movl %edi, %eax # return n
addq $24, %rsp # release locals space on stack
popq %rbp
retq
The main program:
#include <stdio.h>
extern unsigned int binom(int, int);
int main() {
int n = 10;
for (int i = 0; i <= n; i++) {
printf("i=%d | %d\n", i, binom(n, i));
}
return 0;
}
And the results:
i=0 | 1
i=1 | 10
i=2 | 45
i=3 | 120
i=4 | 210
i=5 | 252
i=6 | 210
i=7 | 120
i=8 | 45
i=9 | 10
i=10 | 1
Related
[Edited]
Could someone explain to me how we get the values of M and N in this problem, going through each line of the corresponding assembly code?
I always get stumped at the movl array2 part.
M and N are constants defined using #define
#define M <some value>
#define N <some value>
int array1[M][N];
int array2[N][M];
int copy(int i, int j)
{
array1[i][j] = array2[j][i];
}
If the above code generates the following assembly code: How do we deduce the values of the constants M and N?
copy:
pushl %ebp
movl %esp, %ebp
pushl %ebx
movl 8(%ebp), %ecx
movl 12(%ebp), %ebx
leal (%ecx, %ecx, 8), %edx
sall $2, %edx
movl %ebx, %eax
sall $4, %eax
subl %ebx, %eax
sall $2, %eax
movl array2(%eax, %ecx, 4), %eax
movl %eax, array1(%edx, %ebx, 4)
popl %ebx
movl %ebp,%esp
popl %ebp
ret
You need to check other parts of the assembly. For example, if you define M and N as 8 both, you will find the following in the assembly
array1:
.zero 256
array2:
.zero 256
because on my machine, int is 4 bytes and 8 times 8 is 64. And 64 * 4 = 256. The sample assembly can be found here .
Alright guys, after much research I was able to find a solution. Correct me if I am wrong.
So going through the following assembly step by step: (Added line numbers for ease)
M and N are constants defined using #define
int array1[M][N];
int array2[N][M];
int copy(int i, int j)
{
array1[i][j] = array2[j][i];
}
copy:
1 pushl %ebp
2 movl %esp, %ebp
3 pushl %ebx
4 movl 8(%ebp), %ecx
5 movl 12(%ebp), %ebx
6 leal (%ecx, %ecx, 8), %edx
7 sall $2, %edx
8 movl %ebx, %eax
9 sall $4, %eax
10 subl %ebx, %eax
11 sall $2, %eax
12 movl array2(%eax, %ecx, 4), %eax
13 movl %eax, array1(%edx, %ebx, 4)
14 popl %ebx
15 movl %ebp,%esp
16 popl %ebp
ret
Push %ebp into stack
%ebp points to %esp
Push %ebx into stack
%ecx equals int i (index for array access)
%ebx equals int j (index for array access)
%edx equals 8 * %ecx + %ecx or 9i
%edx equals 36i after a left binary shift of 2
%eax equals %ebx or j
%eax equals 16j after a left binary shift of 4
%eax equals %eax - %ebx = 16j - j = 15j
%eax equals 60j after a left binary shift of 2
%eax equals array2 element with index [4%ecx + %ebx] or [4i + 60j]
Element with index [ 4%ebx + %edx ] or [ 4j + 36i ] of array1 equals %eax or [4i + 60j]
A swap of the two array elements done in 12 and 13 using %eax as
intermediary register.
%ebx popped
%esp's old value restored
%ebp popped
Now we assume array1[i][j]'s element access to be equal to 4Ni + 4j
And array2[j][i]'s element access to be equal to 4Mj + 4i.
( The 4 in each index term as int is of 4 bytes and i, j are individual offsets from starting array location )
This is true because C stores arrays in a row major form.
So equating we get, M = 15 and N = 9.
I intend to do this in C:
#include<stdio.h>
int main() {
int arr[5];
arr[0] = 5;
arr[1] = 0;
arr[2] = 1;
arr[3] = 3;
arr[4] = 4;
int max = 0;
for(int i = 0;i < 5;i++)
if(max < arr[i])
max = arr[i];
printf("%d\n", max);
return 0;
}
This is my code link: array_max.s. This is my assembly code in AT&T format :
.data
.text
.globl _start
_start:
movl $5, -20(%ebp)
movl $0, -16(%ebp)
movl $1, -12(%ebp)
movl $3, -8(%ebp)
movl $4, -4(%ebp)
movl $0, %ecx
movl $5, %eax
loop:
cmp $0, %eax
je terminate
cmp %ecx, -20(%ebp,%eax,4)
jg assign
jmp loop
terminate:
movl $4, %eax
movl $1, %ebx
movl $1, %edx
int $0x80
movl $1, %eax
int $0x80
ret
assign:
movl -20(%ebp,%eax,4), %ecx
ret
I am having a segmentation fault on the very first instruction movl $5, -20(%ebp). I am new to this, please help.
I am having a segmentation fault on the very first instruction movl $5, -20(%ebp).
You are not allocating any space on the stack for arr (i.e.: int arr[5]):
pushl %ebp
movl %esp, %ebp
subl $20,%esp //<--- memory allocation
In order to deallocate the memory allocated on the stack by restoring the previous stack frame, use the leave instruction just before ret.
I am a beginner in Assembly(x86 ATT Syntax). I am working on an assignment where I have to go through each index of a 2d array and find the number of 1's. The method takes in 2d int array,int w, int h. How do I implement the loop to go go from 0 to w and bounce out with loop instruction. I know how to do it with a jmp instruction but loop just gives me errors/segFaults. This is my attempt with a jump statement and it works. How would I go about converting the inner loop using a loop instruction?
pushl %ebp
movl %esp, %ebp
movl $0, -4(%ebp)
movl $0, -8(%ebp)
movl $0, -12(%ebp)
movl $0, -4(%ebp) #outside loop
jmp .L10
.L14: #Inner Loop
movl $0, -8(%ebp)
jmp .L11
.L13:
movl -4(%ebp), %eax
leal 0(,%eax,4), %edx
movl 8(%ebp), %eax
addl %edx, %eax
movl (%eax), %eax
movl -8(%ebp), %edx
sall $2, %edx
addl %edx, %eax
movl (%eax), %eax
cmpl $1, %eax
jne .L12
addl $1, -12(%ebp)
.L12:
addl $1, -8(%ebp)
.L11: #check inner loop
movl -8(%ebp), %eax
cmpl 12(%ebp), %eax
jl .L13
addl $1, -4(%ebp)
.L10: #check outside loop
movl -4(%ebp), %eax
cmpl 16(%ebp), %eax
jl .L14
movl -12(%ebp), %eax
leave
ret
Generally using loop has no advantages except maybe smaller code. It's usually slower and less flexible, thus not recommended.
That said, if you still want to use it you should know that it employs the ecx register for counting down to zero. So you need to restructure your code to accommodate that. In your case, that means loading ecx with the value of w and letting it count down. You will also need to apply an offset of -1 during indexing, since your current loop variable goes from 0 to w-1, but ecx will go from w down to 1 (inclusive).
Furthermore, the loop instruction is used after the loop body, that is it implements a do-while loop. To skip the loop body if the count is zero a companion instruction, JECXZ, can be used.
You can use lodsl (which moves %esi up by default) and loop (which moves %ecx down) in tandem. I am not sure if it is more efficient than what gcc generates from c, which is basically your code, but it looks prettier.
What I have done here doesn't answer your question precisely -- rather than use loop for the inner loop I have assumed the whole array is stored contiguously and then there is only a single loop to worry about. When compiling from c on my machine, it is stored contiguously, but I'm not sure you should rely on that. Hopefully what I have done gives you enough to understand how loop and lodsl work, and you can modify your code to use them just in the inner loop.
.data
x:
.long 6
y:
.long 5
array:
.long 1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1
.text
.global _start
_start:
# set up for procedure call
push x
push y
push $array
# call and cleanup
call cnt
add $0xc, %esp
# put result in %ebx and finish up
#(echo $? gives value in bash if <256)
mov %eax, %ebx
mov $1, %eax
int $0x80
# %ebx will hold the count of 1s
# %ecx will hold the number of elements to check
# %esi will hold the address of the first element
# Assumes elements are stored contiguously in memory
cnt:
# do progogue
enter $0, $1
# set %ebx to 0
xorl %ebx, %ebx
# grab x and y parameters from stack and
# multiply together to get the number of elements
# in the array
movl 0x10(%ebp), %eax
movl 0xc(%ebp), %ecx
mul %ecx
movl %eax, %ecx
# get address of first element in array
movl 0x8(%ebp), %esi
getel:
# grab the value at the address in %esi and increment %esi
# it is put in %eax
lodsl
# if the value in %eax is 1, increment %ebx
cmpl $1, %eax
jne ne
incl %ebx
ne:
# decrement %ecx and if it is greater than 0, keep going
loop getel
# %ecx is zero so we are done. Put the count in %eax
movl %ebx, %eax
# do epilogue
leave
ret
It really is prettier without all the comments.
.data
x:
.long 6
y:
.long 5
array:
.long 1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1
.text
.global _start
_start:
push x
push y
push $array
call cnt
add $0xc, %esp
mov %eax, %ebx
mov $1, %eax
int $0x80
cnt:
enter $0, $1
xorl %ebx, %ebx
movl 0x10(%ebp), %eax
movl 0xc(%ebp), %ecx
mul %ecx
movl %eax, %ecx
movl 0x8(%ebp), %esi
getel:
lodsl
cmpl $1, %eax
jne ne
incl %ebx
ne:
loop getel
movl %ebx, %eax
leave
ret
I have this IA32 assembly language code I'm trying to convert into regular C code.
.globl fn
.type fn, #function
fn:
pushl %ebp #setup
movl $1, %eax #setup 1 is in A
movl %esp, %ebp #setup
movl 8(%ebp), %edx # pointer X is in D
cmpl $1, %edx # (*x > 1)
jle .L4
.L5:
imull %edx, %eax
subl $1, %edx
cmpl $1, %edx
jne .L5
.L4:
popl %ebp
ret
The trouble I'm having is deciding what type of comparison is going on. I don't get how the program gets to the L5 cache. L5 seems to be a loop since there's a comparison within it. I'm also unsure of what is being returned because it seems like most of the work is done is the %edx register, but doesn't go back to %eax for returning.
What I have so far:
int fn(int x)
{
}
It looks to me like it's computing a factorial. Ignoring the stack frame manipulation and such, we're left with:
movl $1, %eax #setup 1 is in A
Puts 1 into eax.
movl 8(%ebp), %edx # pointer X is in D
Retrieves a parameter into edx
imull %edx, %eax
Multiplies eax by edx, putting the result into eax.
subl $1, %edx
cmpl $1, %edx
jne .L5
Decrements edx and repeats if edx != 1.
In other words, this is roughly equivalent to:
unsigned fact(unsigned input) {
unsigned retval = 1;
for ( ; input != 1; --input)
retval *= input;
return retval;
}
I just write a simple program to learn c programming
1 #include<stdio.h>
2
3 int main()
4 {
5 int a = 5;
6 switch(a)
7 {
8 case 0:
9 {
10 ;
11 int a = 10;
12 printf("%d\n",a);
13 break;
14 }
15 default :
16 printf("%d",a);
17
18 }
19 return 0;
20 }
Output: 5
When I forgot the brace it turns to be:
8 case 0:
9
10 ;
11 int a = 10;
12 printf("%d\n",a);
13 break;
14
Output: 0
I'm little confused about this and try to compile and debug:
- 1 0x000000000040051c <+0>: push %rbp |- 1 0x000000000040051c <+0>: push %rbp
| 2 0x000000000040051d <+1>: mov %rsp,%rbp || 2 0x000000000040051d <+1>: mov %rsp,%rbp
| 3 0x0000000000400520 <+4>: sub $0x10,%rsp || 3 0x0000000000400520 <+4>: sub $0x10,%rsp
| 4 => 0x0000000000400524 <+8>: movl $0x5,-0x8(%rbp) || 4 => 0x0000000000400524 <+8>: movl $0x5,-0x8(%rbp)
| 5 0x000000000040052b <+15>: mov -0x8(%rbp),%eax || 5 0x000000000040052b <+15>: mov -0x8(%rbp),%eax
| 6 0x000000000040052e <+18>: test %eax,%eax || 6 0x000000000040052e <+18>: test %eax,%eax
| 7 0x0000000000400530 <+20>: jne 0x40054f <main+51> || 7 0x0000000000400530 <+20>: jne 0x40054f <main+51>
| 8 0x0000000000400532 <+22>: movl $0xa,-0x4(%rbp) || 8 0x0000000000400532 <+22>: movl $0xa,-0x4(%rbp)
9 0x0000000000400539 <+29>: mov -0x4(%rbp),%eax | 9 0x0000000000400539 <+29>: mov -0x4(%rbp),%eax
10 0x000000000040053c <+32>: mov %eax,%esi | 10 0x000000000040053c <+32>: mov %eax,%esi
11 0x000000000040053e <+34>: mov $0x400614,%edi | 11 0x000000000040053e <+34>: mov $0x400614,%edi
12 0x0000000000400543 <+39>: mov $0x0,%eax | 12 0x0000000000400543 <+39>: mov $0x0,%eax
13 0x0000000000400548 <+44>: callq 0x4003f0 <printf#plt> | 13 0x0000000000400548 <+44>: callq 0x4003f0 <printf#plt>
14 0x000000000040054d <+49>: jmp 0x400563 <main+71> | 14 0x000000000040054d <+49>: jmp 0x400563 <main+71>
15 0x000000000040054f <+51>: mov -0x8(%rbp),%eax | 15 0x000000000040054f <+51>: mov -0x4(%rbp),%eax
16 0x0000000000400552 <+54>: mov %eax,%esi | 16 0x0000000000400552 <+54>: mov %eax,%esi
17 0x0000000000400554 <+56>: mov $0x400618,%edi | 17 0x0000000000400554 <+56>: mov $0x400618,%edi
18 0x0000000000400559 <+61>: mov $0x0,%eax | 18 0x0000000000400559 <+61>: mov $0x0,%eax
19 0x000000000040055e <+66>: callq 0x4003f0 <printf#plt> | 19 0x000000000040055e <+66>: callq 0x4003f0 <printf#plt>
20 0x0000000000400563 <+71>: mov $0x0,%eax | 20 0x0000000000400563 <+71>: mov $0x0,%eax
21 0x0000000000400568 <+76>: leaveq | 21 0x0000000000400568 <+76>: leaveq
+ 22 +-- 2 lines: 0x0000000000400569 <+77>: retq ----------------------|+ 22 +-- 2 lines: 0x0000000000400569 <+77>: retq ---------------------
A little diffrent but vital:
$ diff with.txt without.txt
15c15
< 0x000000000040054f <+51>: mov -0x8(%rbp),%eax
---
> 0x000000000040054f <+51>: mov -0x4(%rbp),%eax
UPDATE:
I learn a lesson that gcc -Wall is always a good practice.
So you have to really work at getting to this point, as it won't compile without the extra semicolon in your code. Which makes me think this is contrived example made up for an interview or some such.
In your second example, the variable a (inner) is created at the switch braces { }, but it is not initialized at that level, since the initialization is only in the case 0: code. So the value of a is completely random (happens to be zero)
Either way, bad coding style! Don't forget to use braces in case-statements if you introduce variables. [In g++ you actually get an error "jump to case-label crosses initialization of 'int a']
So, first of all, gcc -Wall will give a warning for "uninitalized variable".
If we consider this example:
int a = 111;
int main()
{
int a = 2;
printf("a=%d\n", a);
}
I don't think anyone would argue the case of "which a do we mean", right?
Or if we have:
int main()
{
int x = 12;
int a = 11;
if(x == 12)
{
int a = 2;
printf("a=%d\n", a);
}
}
Again, it's pretty obvious what's going on here, right?
If we rewrite your code to show what actually happens:
int main()
{
int a = 5;
switch(a)
{
int a;
case 0:
a=10 ;
printf("%d\n",a);
break;
default :
printf("%d",a);
}
return 0;
}
Now, that's semantically the same thing as your code in the second variant. It just looks a bit different!
Without '{}', you just jump over the initialization of the inner variable 'a' (it still defined, though), so you get an uninitialized 'a', in this case, it is '0'.
BTW, with '{}', it should output '5'.
I appreciate the usage of assembly here in the post as
it helps to understand the code in a better way.
Now what happened here.
Lets discuss this issue in cases
case 1 :
#include<stdio.h>
int main()
{
int a=5;
switch(a)
{
case 0:
{
;
int a = 10;
printf("%d in case 0\n",a);
break;
;
}
default:
printf("%d in default case\n",a);
break;
}
return 0;
}
Case 1 Assembly:
.file "test1.c"
.section .rodata
.LC0:
.string "%d in case 0\n"
.LC1:
.string "%d in default case\n"
.text
.globl main
.type main, #function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $5, 28(%esp)
movl 28(%esp), %eax
testl %eax, %eax
jne .L6
.L3:
movl $10, 24(%esp)
movl $.LC0, %eax
movl 24(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
jmp .L4
.L6:
movl $.LC1, %eax
movl 28(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
.L4:
movl $0, %eax
leave
ret
case 1 o/p:
root#local-host#./a.out
5 in default case
Explanation :
This is as expected because as you can see the statement in assembly
movl $5, 28(%esp)
we are copying / moving 5 to 28(%esp) location
movl 28(%esp), %eax
testl %eax, %eax its a switch equivalent
in main tag
here 28(%esp) is nothing but the value of a (int a=5;)
And at L3 all 24(%esp) is used to store the value 10
Please note that ebx register is used hereas new a.
And L6 is the default case now look at the following statement
movl 28(%esp), %edx
here 28(%esp) (which is nothing but value of a) is copied to o/p hence our o/p is as expected.
Case 2:
include
int main()
{
int a=5;
switch(a)
{
case 0:
;
int a = 10;
printf("%d in case 0\n",a);
break;
default:
printf("%d in default case\n",a);
break;
}
return 0;
}
Case 2 Assembly:
.file "test1.c"
.section .rodata
.LC0:
.string "%d in case 0\n"
.LC1:
.string "%d in default case\n"
.text
.globl main
.type main, #function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $5, 28(%esp)
movl 28(%esp), %eax
testl %eax, %eax
jne .L6
.L3:
movl $10, 24(%esp)
movl $.LC0, %eax
movl 24(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
jmp .L4
.L6:
movl $.LC1, %eax
movl 24(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
.L4:
movl $0, %eax
leave
ret
Case 2 o/p:
root#local-host#./a.out
134513723 in default case
A garbage value
Let me explain here also the 28(%esp) is the value of a
Now take a close look at L3 and L6 labels
Here is what you find during the code at 24%esp again a is created only if the case 0 satisfies.
As the case of 0 is not satisfied the 24%esp will not get initialised i.e int a = 10;
And we are going to default which is L6 and we are trying to get 24%esp value which is not yet
initilised (but it is a valid location) as we havent went to case 0.
Thats why we are getting garbage value.
Case 3:
include
int main()
{
int a=5;
switch(a)
{
case 5:
;
int a = 10;
printf("%d in case 5\n",a);
default:
printf("%d in default case\n",a);
break;
}
return 0;
}
Case 3 assembly:
.file "test1.c"
.section .rodata
.LC0:
.string "%d in case 5\n"
.LC1:
.string "%d in default case\n"
.text
.globl main
.type main, #function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $5, 28(%esp)
movl 28(%esp), %eax
cmpl $5, %eax
jne .L2
.L3:
movl $10, 24(%esp)
movl $.LC0, %eax
movl 24(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
.L2:
movl $.LC1, %eax
movl 24(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
movl $0, %eax
leave
ret
Case 3 o/p:
root#local-host#./a.out
10 in case 0
10 in default case
Here as you can see that the new a is created at 24(%esp) and initailised at case 5 so the value will be same
at default location.
In L3 label
movl 24(%esp), %edx
In L2 Label
movl 24(%esp), %edx
So same location 24(%esp) is used which is created and initialised at cse 5 and flow through the default.
Case 4:
include
int main()
{
int a=5;
switch(a)
{
case 0:
;
static int a = 10;
printf("%d in case 0\n",a);
break;
default:
printf("%d in default\n",a);
break;
}
return 0;
}
Case 4 Assembley:
.file "test1.c"
.section .rodata
.LC0:
.string "%d in case 0\n"
.LC1:
.string "%d in default\n"
.text
.globl main
.type main, #function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $5, 28(%esp)
movl 28(%esp), %eax
testl %eax, %eax
jne .L6
.L3:
movl a.1706, %edx
movl $.LC0, %eax
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
jmp .L4
.L6:
movl a.1706, %edx
movl $.LC1, %eax
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
.L4:
movl $0, %eax
leave
ret
.size main, .-main
.data
.align 4
.type a.1706, #object
.size a.1706, 4
a.1706:
.long 10
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5.1) 4.4.5"
.section .note.GNU-stack,"",#progbits
Case 4 O/p:
root#local-host#./a.out
10 in default
This makes sense as the static type is a global and stored in the data section so
During execution the global value i.e the static int a is in data section and initialized as 10.
Case 5:
include
int main()
{
int a=5;
switch(a)
{
case 0:
{
;
static int a = 10;
printf("%d in case 0\n",a);
break;
}
default:
printf("%d in default\n",a);
break;
}
return 0;
}
Case 5 Assembly:
.file "test1.c"
.section .rodata
.LC0:
.string "%d in case 0\n"
.LC1:
.string "%d in default\n"
.text
.globl main
.type main, #function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $5, 28(%esp)
movl 28(%esp), %eax
testl %eax, %eax
jne .L6
.L3:
movl a.1706, %edx
movl $.LC0, %eax
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
jmp .L4
.L6:
movl $.LC1, %eax
movl 28(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
.L4:
movl $0, %eax
leave
ret
.size main, .-main
.data
.align 4
.type a.1706, #object
.size a.1706, 4
a.1706:
.long 10
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5.1) 4.4.5"
.section .note.GNU-stack,"",#progbits
Case 5 O/p:
root#local-host#./a.out
5 in default
Here due to the '{' delimiters the static value is confined to case 0 at assembler stage
the default case is still getting the value from 28(%esp) which is as expected as at assemble time case 0 has static and is out of scope for default.
You can try different formats by removing breaks and applying '{' '}' delimiters
Never forget to look it in terms of scope and wrto assembly code.