I translated a simple c program into IA32 and then transliterated it into Y86 but I am getting an error I don't understand or know how to debug since I am just learning Y86. The error is:
Stopped in 1 steps at PC = 0x1. Exception 'HLT', CC Z=1 S=0 O=0
Changes to registers:
Changes to memory:
The program is supposed to initialize i to 0 and then proceed through a for loop until i is greater than or equal to 5 and increment i each time. Inside the for loop I set j equal to i*2 and k is equal to j+1. My Y86 code is as follows:
main:
irmovl $0, %ebx
jmp L2
halt
L3:
rrmovl %ebx, %eax
addl %eax, %eax
rrmovl %eax, %ecx
rrmovl %ecx, %eax
irmovl $1, %esi
addl %esi, %eax
rrmovl %eax, %edx
addl %esi, %ebx
L2:
irmovl $4, %edi
subl %edi, %ebx
jle L3
I can provide the C code and IA32 code I transliterated from if it would help you answer my problem I really need some help thanks.
You forgot to add the extra NL (CR) in the source file. YAS is flawed. When it assembles it wraps the assembly around if there is no NL (CR) at the end of the source (ys) file, overwriting the beginning of the created object code (yo) file.
The result... well it is bad. In your case, YAS probably inserted a HLT instruction in the first character of the object file.
Related
Just starting to learn assembly, so I am having trouble with some basic. For example, I am trying to modify a file that normally runs to find the maximum value.
What I am trying to do is iterate through the data_items and modify it by changing the list item, while still maintaining its ability to execute to find the maximum value.
I have tried modifying the start_loop to include an addl data_items, 0x01 but it errors out since it only pulls the first value.
I then adjusted it to do something like addl data_items(,%esi,4), 0x01 and iterate through adjusting it but that didn't work either. I know this is probably very simplistic, but I can't seem to find a method that works.
#
.section .data
data_items: #These are the data items trying to modify and store
.long 3,67,34,222,45,75,54,34,44,33,22,11,66,0
.section .text
.globl _start
_start:
movl $0, %edi
movl data_items(,%edi,4), %eax
movl %eax, %ebx
start_loop:
cmpl $0, %eax
je loop_exit
incl %edi
movl data_items(,%edi,4), %eax
cmpl %ebx, %eax
jle start_loop
movl %eax, %ebx
jmp start_loop
loop_exit:
movl $1, %eax
int $0x80
Once you have an array element in %eax just increment the memory that was last used to read %eax from:
start_loop:
cmpl $0, %eax ; Not actual element if this is 0
je loop_exit
incl data_items(,%edi,4) <<<<<<<<<<<<<<<<<
incl %edi
movl data_items(,%edi,4), %eax
This does not mess with the current finding of the max value. Only next time will the max value be 1 greater.
So I've been working on a problem (and before you ask, yes, it is homework, but I've been putting in faithful effort!) where I have some assembly code and want to be able to convert it (as faithfully as possible) to C.
Here is the assembly code:
A1:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl $0, -4(%ebp)
jmp .L2
.L4:
movl -4(%ebp), %eax
sall $2, %eax
addl 8(%ebp), %eax
movl (%eax), %eax
cmpl 12(%ebp), %eax
jg .L6
.L2:
movl -4(%ebp), %eax
cmpl 16(%ebp), %eax
jl .L4
jmp .L3
.L6:
nop
.L3:
movl -4(%ebp), %eax
leave
ret
And here's some of the C code I wrote to mimic it:
int A1(int a, int b, int c) {
int local = 0;
while(local < c) {
if(b > (int*)((local << 2) + a)) {
return local;
}
}
return local;
}
I have a few questions about how assembly works.
First, I notice that in L4, the body of the while loop, nothing is ever assigned to local. It's initialized to be 0 at the start of the function, and then never modified again. Looking at the C code I made for it, though, that seems odd, considering that the loop will go on indefinitely if the if-condition fails. Am I missing something there? I was under the impression that you'd need a snippet of code like:
movl %eax, -4(%ebp)
in order to actually assign anything to the local variable, and I don't see anything like that in the body of the while loop.
Secondly, you'll see that in the assembly code, the only local variable that's declared is "local". Hence, I have to use a snippet of code like:
if(b > (int*)((local << 2) + a))
The output of this line doesn't look much like the assembly code, though, and I think I might have made a mistake. What did I do wrong here?
And finally (thanks for your patience!), on a related note, I understand that the purpose of this if-loop in the while loop is to break out if the condition is fulfilled, and then to return local. Hence L6 and "nop" (which is basically saying nothing). However, I don't know how to replicate this in my program. I've tried "break", and I've tried returning local as you see here. I understand the functionality - I just don't know how to replicate it in C (short of using goto, but that kind of defeats the purpose of the exercise...).
Thank you for your time!
This is my guess:
int A1 (int *a, int value, int size)
{
int i = 0;
while (i<size)
{
if (a[i] <= value)
break;
}
return i;
}
Which, compiled back to assembly, gives me this code:
A1:
.LFB0:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl $0, -4(%ebp)
jmp .L2
.L4:
movl -4(%ebp), %eax
leal 0(,%eax,4), %edx
movl 8(%ebp), %eax
addl %edx, %eax
movl (%eax), %eax
cmpl 12(%ebp), %eax
jg .L2
jmp .L3
.L2:
movl -4(%ebp), %eax
cmpl 16(%ebp), %eax
jl .L4
.L3:
movl -4(%ebp), %eax
leave
ret
Now this seems to be identical to your original ASM code, just the code starting at L4 is not the same, but if we anotate both codes:
ORIGINAL
movl -4(%ebp), %eax ;EAX = local
sall $2, %eax ;EAX = EAX*4
addl 8(%ebp), %eax ;EAX = EAX+a, hence EAX=a+local*4
ASM-C-ASM
movl -4(%ebp), %eax ;EAX = i
leal 0(,%eax,4), %edx ;EDX = EAX*4
movl 8(%ebp), %eax ;EAX = a
addl %edx, %eax ;EAX = EAX+EDX, hence EAX=a+i*4
Both codes continue with
movl (%eax), %eax
Because of this, I guess a is actually a pointer to some variable type that uses 4 bytes. By the comparison between the second argument and the value read from memory, I guess that type must be either int or long. I choose int solely by convenience.
Of course this also means that this code (and the original one) does not make any sense. It lacks the i++ part somewhere. If this is so, then a is an array, and the third argument is the size of the array. I've named my local variable i to keep with the tradition of naming index variables like this.
This code would scan the array searching for a value inside it that is equal or less than value. If it finds it, the index to that value is returned. If not, the size of the array is returned.
.data
arr: .long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
arr_size: .long 10
in: .string "%d"
.text
.global main
main:
#scanf
movl $0, %ecx # index i
scanloop:
cmpl arr_size, %ecx
je endscan # if ecx == 10 -> break
leal arr(, %ecx, 4), %eax # load the address of arr[i] into eax
pushl (%eax) # push the value that is being pointed at onto the stack
pushl $in
call scanf
addl $8, %esp
incl %ecx
jmp scanloop
#endscanf
endscan:
#...
I don't know how to "scanf" values into an array. I thought it'd work if I calculate the address of each index, push the value that the address points to onto the stack and call scanf. But I get a memory access error.
So, is there a way to do it like that?
For reasons I cannot tell it works if I use %edi instead of %ecx as my index.
I still don't know how to use a debugger, so I printed out my index in every iteration to see what's wrong. The thing was that %ecx never got beyond 1, which made the procedure stuck in an infinite loop.
With %edi, however, incrementation works perfectly fine.
PS: Out of curiosity I've tried other registers as well, namely %esi and %ebx. It also works for them. If I ever find out the reasons for this, I'll refer back to this post.
Edit: Ok, the mistake was a silly one. I didn't obey to the calling conventions.
So scanf, like printf, apparently changes register values. By convention, %eax, %ecx and %edx are caller-save, whereas %ebx, %edi and %esi are callee-save.
Because I, as the caller, didn't save %ecx prior to the call to scanf, I got an unwanted value in %ecx.
It worked for %edi, %esi and %ebx because these are callee-save, hence guaranteed to be not changed by the called function. So if I had tried %eax or %edx instead, it most likely wouldn't have worked either.
And yes, it works perfectly fine if I push %ecx on the stack before calling scanf.
Edit2:
Oh, and solved the issue with the access problem by making myself a global variable in which I scan a number, and move that number into the desired index:
.data
num: .long 0
#...
scanloop:
cmpl arr_size, %ecx
je endscan # if ecx == 10 -> break
pushl %ecx #caller-save
pushl $num
pushl $in
call scanf
addl $8, %esp
popl %ecx #restore
movl num, %eax #in order to avoid two memory arguments to movl
leal arr(, %ecx, 4), %edx #calculate address of index
movl %eax, (%edx) #store num in that index
incl %ecx
jmp scanloop
#endscanf
#...
I am experiencing some difficulties interpreting this exercise;
What does exactly xorl does in this assembly snippet?
C Code:
int i = 0;
if (i>=55)
i++;
else
i--;
Assembly
xorl ____ , %ebx
cmpl ____ , %ebx
Jel .L2
____ %ebx
.L2:
____ %ebx
.L3:
What's happening on the assembly part?
It's probably:
xorl %ebx, %ebx
This is a common idiom for zeroing a register on x86. This would correspond with i = 0 in the C code.
If you are curious "but why ?" the short answer is that the xor instruction is fewer bytes than mov $0, %ebx. The long answer includes other subtle reasons.
I am leaving out the rest of the exercise since there's nothing idiosyncratic left.
This is the completed and commented assembly equivalent to your C code:
xorl %ebx , %ebx ; i = 0
cmpl $54, %ebx
jle .L2 ; if (i <= 54) jump to .L2, otherwise continue with the next instruction (so if i>54... which equals >=55 like in your C code)
addl $2, %ebx ; >54 (or: >=55)
.L2:
decl %ebx ; <=54 (or <55, the else-branch of your if) Note: This code also gets executed if i >= 55, hence why we need +2 above so we only get +1 total
.L3:
So, these are the (arithmetic) instructions that get executed for all numbers >=55:
addl $2, %ebx
decl %ebx
So for numbers >=55, this is equal to incrementing. The following (arithmetic) instructions get executed for numbers <55:
decl %ebx
We jump over the addl $2, %ebx instruction, so for numbers <55 this is equal to decrementing.
In case you're not allowed to type addl $2, (since it's not just the instruction but also an argument) into a single blank there's probably an error in the asm code you've been given (missing a jump between line 4 and 5 to .L3).
Also note that jel is clearly a typo for jle in the question.
XORL is used to initialize a register to Zero, mostly used for the counter. The code from ccKep is correct, only that he incremented by a wrong value ie. 2 instead of 1. The correct version is therefore:
xorl %ebx , %ebx # i = 0
cmpl $54, %ebx # compare the two
jle .L2 #if (i <= 54) jump to .L2, otherwise continue with the next instruction (so if i>54... which equals >=55 like in your C code)
incl %ebx #i++
jmp .DONE # jump to exit position
.L2:
decl %ebx # <=54 (or <55
.DONE:
Wanting to see the output of the compiler (in assembly) for some C code, I wrote a simple program in C and generated its assembly file using gcc.
The code is this:
#include <stdio.h>
int main()
{
int i = 0;
if ( i == 0 )
{
printf("testing\n");
}
return 0;
}
The generated assembly for it is here (only the main function):
_main:
pushl %ebpz
movl %esp, %ebp
subl $24, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
call __alloca
call ___main
movl $0, -4(%ebp)
cmpl $0, -4(%ebp)
jne L2
movl $LC0, (%esp)
call _printf
L2:
movl $0, %eax
leave
ret
I am at an absolute loss to correlate the C code and assembly code. All that the code has to do is store 0 in a register and compare it with a constant 0 and take suitable action. But what is going on in the assembly?
Since main is special you can often get better results by doing this type of thing in another function (preferably in it's own file with no main). For example:
void foo(int x) {
if (x == 0) {
printf("testing\n");
}
}
would probably be much more clear as assembly. Doing this would also allow you to compile with optimizations and still observe the conditional behavior. If you were to compile your original program with any optimization level above 0 it would probably do away with the comparison since the compiler could go ahead and calculate the result of that. With this code part of the comparison is hidden from the compiler (in the parameter x) so the compiler can't do this optimization.
What the extra stuff actually is
_main:
pushl %ebpz
movl %esp, %ebp
subl $24, %esp
andl $-16, %esp
This is setting up a stack frame for the current function. In x86 a stack frame is the area between the stack pointer's value (SP, ESP, or RSP for 16, 32, or 64 bit) and the base pointer's value (BP, EBP, or RBP). This is supposedly where local variables live, but not really, and explicit stack frames are optional in most cases. The use of alloca and/or variable length arrays would require their use, though.
This particular stack frame construction is different than for non-main functions because it also makes sure that the stack is 16 byte aligned. The subtraction from ESP increases the stack size by more than enough to hold local variables and the andl effectively subtracts from 0 to 15 from it, making it 16 byte aligned. This alignment seems excessive except that it would force the stack to also start out cache aligned as well as word aligned.
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
call __alloca
call ___main
I don't know what all this does. alloca increases the stack frame size by altering the value of the stack pointer.
movl $0, -4(%ebp)
cmpl $0, -4(%ebp)
jne L2
movl $LC0, (%esp)
call _printf
L2:
movl $0, %eax
I think you know what this does. If not, the movl just befrore the call is moving the address of your string into the top location of the stack so that it may be retrived by printf. It must be passed on the stack so that printf can use it's address to infer the addresses of printf's other arguments (if any, which there aren't in this case).
leave
This instruction removes the stack frame talked about earlier. It is essentially movl %ebp, %esp followed by popl %ebp. There is also an enter instruction which can be used to construct stack frames, but gcc didn't use it. When stack frames aren't explicitly used, EBP may be used as a general puropose register and instead of leave the compiler would just add the stack frame size to the stack pointer, which would decrease the stack size by the frame size.
ret
I don't need to explain this.
When you compile with optimizations
I'm sure you will recompile all fo this with different optimization levels, so I will point out something that may happen that you will probably find odd. I have observed gcc replacing printf and fprintf with puts and fputs, respectively, when the format string did not contain any % and there were no additional parameters passed. This is because (for many reasons) it is much cheaper to call puts and fputs and in the end you still get what you wanted printed.
Don't worry about the preamble/postamble - the part you're interested in is:
movl $0, -4(%ebp)
cmpl $0, -4(%ebp)
jne L2
movl $LC0, (%esp)
call _printf
L2:
It should be pretty self-evident as to how this correlates with the original C code.
The first part is some initialization code, which does not make any sense in the case of your simple example. This code would be removed with an optimization flag.
The last part can be mapped to C code:
movl $0, -4(%ebp) // put 0 into variable i (located at -4(%ebp))
cmpl $0, -4(%ebp) // compare variable i with value 0
jne L2 // if they are not equal, skip to after the printf call
movl $LC0, (%esp) // put the address of "testing\n" at the top of the stack
call _printf // do call printf
L2:
movl $0, %eax // return 0 (calling convention: %eax has the return code)
Well, much of it is the overhead associated with the function. main() is just a function like any other, so it has to store the return address on the stack at the start, set up the return value at the end, etc.
I would recommend using GCC to generate mixed source code and assembler which will show you the assembler generated for each sourc eline.
If you want to see the C code together with the assembly it was converted to, use a command line like this:
gcc -c -g -Wa,-a,-ad [other GCC options] foo.c > foo.lst
See http://www.delorie.com/djgpp/v2faq/faq8_20.html
On linux, just use gcc. On Windows down load Cygwin http://www.cygwin.com/
Edit - see also this question Using GCC to produce readable assembly?
and http://oprofile.sourceforge.net/doc/opannotate.html
You need some knowledge about Assembly Language to understand assembly garneted by C compiler.
This tutorial might be helpful
See here more information. You can generate the assembly code with C comments for better understanding.
gcc -g -Wa,-adhls your_c_file.c > you_asm_file.s
This should help you a little.