Consider the C source code statements shown below.
struct person
{
char name[30];
int id;
int points;
};
char Fmt[] = "Name: %s ID: %d Points: %d\n";
void display_one( struct person List[], int I )
{
printf( Fmt, List[I].name, List[I].id, List[I].points );
}
Complete the SPARC assembly language code segment below so that the sequence
of assembly language statements is equivalent to the C statements above.
.section ".data"
.align 4
Fmt: .asciz "Name: %s ID: %d Points: %d\n"
.global display_one
.section ".text"
.align 4
display_one:
save %sp, -96, %sp
smul %i1, 40, %l1
add %i0, %l1, %l0
set Fmt, %o0
mov %l0, %o1
ld [%l0+32], %o2
ld [%l0+36], %o3
call printf
nop
ret
restore
I was wondering what the smul %i1, 40, %l1 line is doing. I don't understand why it is multiplying by 40. If anyone could explain that would be great. Thanks.
40 is the size of struct person:
char name[30]; // 30 bytes
// 2 bytes padding to make the following int aligned
int id; // 4 bytes
int points; // 4 bytes
The parameter I is multiplied by 40 to compute the address of List[I].
Related
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'm trying to do the following for the sake of practice in NASM:
1)Read a string from command-line in C
2)Pass that string to a NASM function which takes the string as its first parameter
3)Return that exact string from NASM function
prefix.asm:
;nasm -f elf32 prefix.asm -o prefix.o
segment .bss
pre resb 256
segment .text
global prefix
prefix:
push ebp ;save the old base pointer value
mov ebp,esp ;base pointer <- stack pointer
mov eax,[ebp+8] ;function argument
add esp, 4
pop ebp
ret
prefix c:
//nasm -f elf32 prefix.asm -o prefix.o
//gcc prefix.c prefix.o -o prefix -m32
#include <stdio.h>
#include <string.h>
char* prefix(char *str);
int main(void)
{
char str[256];
char* pre;
int a;
printf("Enter string: ");
scanf("%s" , str) ;
pre = prefix(str);
printf("Prefix array: %s\n", pre);
return 0;
}
After I run(it compiles w/o any problem) and supply my string to the program I get a Segmentation fault (core dumped) error.
First try to write a C program to implement char* prefix(char *str), disassemble it and understand it.
Problem 1: the add esp, 4 should be deleted. A function should preserve the stack pointer. I.e. the esp should be the same before the first instruction and before the return instruction. Your assembly code increases esp by 4.
Problem 2: Don't name your .asm and .c to be the same. Use different names.
When I try to store something from register to memory, I received Segmentation fault error. As I used gdb to debug line by line, it shows up Program received signal SIGSEGV when comes to the line of stb.
What I tried to do is to implement the standard C strcat function in PowerPC Assembly.
Here's the main C program, pretty simple.
#include<stdio.h>
extern char *mystrcat(char *first, char *second);
int main(){
char *first, *second, *third;
first = "ab";
second = "cd";
third = mystrcat(first, second);
printf("%s\n", third);
return 0;
}
And this is my mystrcat.s powerpc assembly file.
.text
.align 2
.globl mystrcat
mystrcat:
mr %r5, %r3
.L1:
lbz %r6, 0(%r5)
cmpdi %r6, 0
beq .L2
addi %r5, %r5, 1
b .L1
.L2:
lbz %r6, 0(%r4)
stb %r6, 0(%r5)
addi %r4, %r4, 1
addi %r5, %r5, 1
cmpdi %r6, 0
beq .L3
b .L2
.L3:
blr
Before the L2 label is the process finding the end of the first string.
Gdb showed up "Program received signal SIGSEGV" at the second line after L2 label.
The stb %r6, 0(%r5) command seems raised the error.
But I just don't get it why it cannot figure out address by 0(%r5).
I've tried other command seems like stbx or stbu but no one works.
Thank you for everyone can give me even just little piece of advice.
Update:
I realized this has something to do with memory.
Since the memory for string is readonly, is there a way that I can allocate new memory inside assembly code? I tried "bl malloc" and "nop" and the behavior beyonds my understanding.
In your main function, you try to concatenate 2 strings with the destination one having no room enough to copy the source one at the end.
Trying to add a (kind of implicit) memory allocation in your function mystrcat will introduce confusion.
Note that the segmentation fault also appears using the standard strcat that you want to mimic.
You should fix you main function, writing something like that:
#include <stdio.h>
extern char *mystrcat(char *first, char *second);
int main(){
char first[8] = "ab";
char *second, *third;
second = "cd";
third = mystrcat(first, second);
printf("%s\n", third);
return 0;
}
String literals are stored in read only section of memory. Any attempt to modify string literals results in undefined behavior.
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.
I have compiled the gcc 4.6.0 for mmix according to http://www.bitrange.com/mmix/install.html. After I try their simple hello world, or any other call to printf with more than the first string, only the first string gets printed. E.g.
lada#:~/f/c> cat hellommix.c
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char **argv)
{
printf ("hello, %s\n", argc > 1 ? argv[1] : "world");
exit (0);
}
lada#:~/f/c> mmix-gcc hellommix.c
lada#:~/f/c> mmix ./a.out "abc"
hello, lada#:~/f/c>
The generated assembly looks like this:
# 1 "hellommix.c"
! mmixal:= 8H LOC Data_Section
.text ! mmixal:= 9H LOC 8B
.section .rodata
.p2align 2
LOC #+(4-#)&3
LC:0 IS #
BYTE "world",#0
.p2align 2
LOC #+(4-#)&3
LC:1 IS #
BYTE "hello, %s",#a,#0
.text ! mmixal:= 9H LOC 8B
.p2align 2
LOC #+(4-#)&3
.global main
main IS #
SUBU $254,$254,24
STOU $253,$254,16
ADDU $253,$254,24
GET $2,rJ
SET $3,$0
SUBU $0,$253,24
STOU $1,$0,0
SUBU $0,$253,12
STTU $3,$0,0
SUBU $0,$253,12
LDT $0,$0,0
SLU $0,$0,32
SR $0,$0,32
CMP $0,$0,1
BNP $0,L:2
SUBU $0,$253,24
LDO $0,$0,0
LDO $0,$0,8
JMP L:3
L:2 IS #
GETA $0,LC:0
L:3 IS #
GETA $5,LC:1
SET $6,$0
PUSHJ $4,printf
PUT rJ,$2
SETL $5,0
PUSHJ $4,exit
.data ! mmixal:= 8H LOC 9B
Try those:
put a fflush (stdout); before exiting. (though normally, posix' man 3 exit tells that all buffers are flushed; maybe something mmix specific)
Dump all arguments, just to see what's there.
-
for (int x=0; x!=argc; ++x) {
printf ("arg %d: \"%s\"\n", x, argv[x]);
}
Enter code:
setbuf(stdout,NULL);
after variable declaration.
Like this, just add setbuf(stdout,NULL); this code. On the first top only. Then you can do the code.