This my C code for my MSP430. I am trying to write str = word_start(str); in assembly but I am not sure if this is correct.
char** tokenize(char* str){
int totalWords = count_words(str);
printf("%d\n", totalWords);
char **array;
array = (char **)malloc(sizeof(char*) * (++totalWords));
//filling the array with individual words
int diff = 0;
int i;
for(i = 0; i < totalWords-1; i++){
str = word_start(str);
// find difference in length
diff = word_terminator(str) - str;
// add new allocated string to array
array[i] = copy_str(str, diff);
// update pointer p to next word
str = word_terminator(str);
}
array[i] = '\0';
return array;
}
This is my assembly code, I want to convert the above method from C to MSP430 assembly.
tokenize:
mov r12, 0(r1) ; put str in str
call #count_words
mov r12 2(r1) ;
mov 2(r1), r12 ; get totalWords
add #1, r12 totalword
add r12, r12
call #malloc
mov r12 4(r1)
mov #0 6(r1) ; int i = 0;
mov #0 8(r1) ; int diff = 0;
top: cmp 0(r1), 6(r1)
JL end
mov 0(r1), r12
call #word_start ; calling word start
mov r12, 0(r1) ; getting the value returned
mov 0(r1), r12
call #word_terminator
mov r12, 8(r1)
mov 0(r1), r12
mov 8(r1), r13
sub r12, r13
call #copy_str
mov r12, 10(r1) ; what we get from cpoy_str put in r12
mov 6(r1), r12 ; put I in r12
add r12, r12 ; add r12
add 4(r1), r12 ; add 4(r1) to whats in r12
mov 10(r1), #r12 ; put what we r12 is in 10(r1)
mov 0(r1), r12
call #word_terminator
move r12, 0(r1)
mov 0(r1), r12
add #1, 6(r1) ; increment i
end:
mov 6(r1), r12
add r12, r12
add 4(r1), r12
mov #0, #r12,
add #12, r1
ret
When I call word_start in assembly, is the way I am passing the value str and getting the value returned done correctly? If not can you show me how you're supposed to pass in variables in assembly to a function and get the returned value from that function?
Related
I have this code in ThreadCreate():
int tmpPSW = newThID << 3;
__asm
PUSH A
PUSH _tmpPSW
__endasm;
This results in:
?ASlink-Warning-Undefined Global '_tmpPSW' referenced by module 'cooperative'
I don't get why. tmpPSW is clearly defined, but sdcc complains. What am I doing wrong here? Is there other way to push C variable in sdcc inline assembly?
Also this is probably relevant. The .asm file generated contains allocation info:
;------------------------------------------------------------
;Allocation info for local variables in function 'ThreadCreate'
;------------------------------------------------------------
;fp Allocated to registers
;newThMask Allocated to registers r6 r7
;newThID Allocated to registers r5
;startSP Allocated to registers r3 r4
;tmp Allocated to registers
;tmpPSW Allocated to registers
;------------------------------------------------------------
Does this mean I run out of registers? If so how should I mitigate this?
EDIT:
Source of ThreadCreate():
// ThreadID is typedef'ed as char
ThreadID ThreadCreate(FunctionPtr fp) {
if (activeTh == 0b1111)
return -1;
// i.e. get rightmost bit 0 in bitmask
// https://stackoverflow.com/a/42747608/6306190
int newThMask = ~activeTh & (activeTh + 1);
activeTh |= newThMask;
ThreadID newThID = 0;
while (newThMask >>= 1) { newThID++; }
int startSP = (newThID ^ (1UL << 2)) << 4;
int tmp = SP;
SP = startSP;
int tmpPSW = newThID << 3;
__asm
PUSH DPL ;; push _fp (argument passed in as DPTR in SDCC)
PUSH DPH ;; push _fp
MOV A, #0
PUSH A ;; ACC
PUSH A ;; B
PUSH A ;; DPL
PUSH A ;; DPH
PUSH _tmpPSW ;; PSW
__endasm;
savedSP[newThID] = SP;
SP = tmp;
return newThID;
}
Generated assembly of ThreadCreate():
;------------------------------------------------------------
;Allocation info for local variables in function 'ThreadCreate'
;------------------------------------------------------------
;fp Allocated to registers
;newThMask Allocated to registers r6 r7
;newThID Allocated to registers r5
;startSP Allocated to registers r3 r4
;tmp Allocated to registers
;tmpPSW Allocated to registers
;------------------------------------------------------------
; cooperative.c:104: ThreadID ThreadCreate(FunctionPtr fp) {
; -----------------------------------------
; function ThreadCreate
; -----------------------------------------
_ThreadCreate:
; cooperative.c:110: if (activeTh == 0b1111)
mov a,#0x0f
cjne a,_activeTh,00121$
clr a
cjne a,(_activeTh + 1),00121$
sjmp 00122$
00121$:
sjmp 00102$
00122$:
; cooperative.c:111: return -1;
mov dpl,#0xff
ret
00102$:
; cooperative.c:119: int newThMask = ~activeTh & (activeTh + 1);
mov a,_activeTh
cpl a
mov r6,a
mov a,(_activeTh + 1)
cpl a
mov r7,a
mov a,#0x01
add a,_activeTh
mov r4,a
clr a
addc a,(_activeTh + 1)
mov r5,a
mov a,r4
anl ar6,a
mov a,r5
anl ar7,a
; cooperative.c:157: activeTh |= newThMask;
mov a,r6
orl _activeTh,a
mov a,r7
orl (_activeTh + 1),a
; cooperative.c:160: while (newThMask >>= 1) { newThID++; }
mov r5,#0x00
00103$:
mov ar3,r6
mov a,r7
mov c,acc.7
rrc a
xch a,r3
rrc a
xch a,r3
mov r4,a
mov ar6,r3
mov ar7,r4
mov a,r3
orl a,r4
jz 00105$
inc r5
sjmp 00103$
00105$:
; cooperative.c:161: int startSP = (newThID ^ (1UL << 2)) << 4;
mov ar3,r5
mov r4,#0x00
mov r6,#0x00
xrl ar3,#0x04
mov a,r4
swap a
anl a,#0xf0
xch a,r3
swap a
xch a,r3
xrl a,r3
xch a,r3
anl a,#0xf0
xch a,r3
xrl a,r3
mov r4,a
; cooperative.c:163: int tmp = SP;
mov r7,_SP
; cooperative.c:164: SP = startSP;
mov _SP,r3
; cooperative.c:176: __endasm;
PUSH DPL ;; push _fp (argument passed in as DPTR in 390)
PUSH DPH ;; push _fp
MOV A, #0
PUSH A ;; ACC
PUSH A ;; B
PUSH A ;; DPL
PUSH A ;; DPH
PUSH _tmpPSW ;; PSW
; cooperative.c:178: savedSP[newThID] = SP;
mov a,r5
add a,r5
add a,#_savedSP
mov r1,a
mov r4,_SP
mov r6,#0x00
mov #r1,ar4
inc r1
mov #r1,ar6
; cooperative.c:179: SP = tmp;
mov _SP,r7
; cooperative.c:180: return newThID;
mov dpl,r5
; cooperative.c:181: }
ret
The compiler optimized your variable away, because it was never used from the view of the compiler. Compare the generated assembly with the source to see this.
You might try other options. Because I don't have SDCC installed, I can just suggest:
Make the variable volatile.
Make the variable static, since one flavor of PUSH works with an address in the internal RAM.
Because inline assembly is heavily depending on the surrounding code and the compiler, you could also use newThID in the assembly part, and do the shift there.
Note 1: The generated assembly demonstrates how slow machine code gets if you use int without thinking. Limit your variables to the smallest appropriate data type.
Note 2: Don't make the variable global. static does what you want without exposing the variable globally: Place it in RAM so it can be accessed.
I'm puzzled over this function.
int i;
for(i = 1; i<10; i++){
int arr[i];
printf("%d\n",sizeof(arr));
}
return 0;
How can the space grow in a bounded (by ESP) stack memory?
Is there a sort of compilation trick?
EDIT for explanation:
Shouldn't the stack be something like that?
0 ---> val of i uninitialized
-4 ---> arr[0] uninitialized
and after the first loop
0 ---> val of i uninitialized
-4 ---> arr[1] uninitialized
-8 ---> arr[0] uninitialized
I'm tempted to say: is ESP moving below each iteration of the loop?
How can the space grow in a bounded size stack memory?
You refer to the space of char arr - its space does not grow. It's a local variable inside the scope of the for loop. So everytime the loop has a new i it's a brand new char arr.
On every loop there is allocated stack for the array and then dealocated.
A bit different example
#include "stdio.h"
#include "string.h"
int h(int x)
{
for(int i = 1; i<x; i++){
char arr[i];
memset(arr, i, sizeof(arr));
printf("%d\n",sizeof(arr));
}
return 0;
}
int main()
{
h(50);
}
in the compiled code
.LC0:
.string "%d\n"
h:
push rbp
mov rbp, rsp
push r13
push r12
mov r12d, edi
push rbx
mov ebx, 1
push rax
.L2:
cmp r12d, ebx
jle .L6
lea rax, [rbx+15]
mov r13, rsp
mov ecx, ebx
mov rsi, rbx
and rax, -16
sub rsp, rax
mov eax, ebx
inc rbx
mov rdi, rsp
rep stosb
mov edi, OFFSET FLAT:.LC0
xor eax, eax
call printf
mov rsp, r13
jmp .L2
.L6:
lea rsp, [rbp-24]
xor eax, eax
pop rbx
pop r12
pop r13
pop rbp
ret
main:
push rax
mov edi, 50
call h
xor eax, eax
pop rdx
ret
lines 15,19 & 20 allocate the space
and thew line 28 deallocates the space for the array
https://godbolt.org/z/msgrc2
Is there a sort of compilation trick?
Yes, sort of. It uses VLAs (https://en.wikipedia.org/wiki/Variable-length_array)
Godbolt is very useful for inspecting things like this:
https://godbolt.org/z/_uR9Ac
As you can see the -Wvla warning is indeed triggered for the line in question.
I am given this assignment:
This program is supposed to search an array of bytes for the value 0xf2. When it finds 0xf2, it should save its location (i.e. address) into the integer variable “f2Address”. If it does not find the value of 0xf2 in the array, it should put a value of 0x00 into the variable “f2Address”. This program has some bugs in it. Fix this program so that it does work properly.
The original code given was:
.label TABLE1_LOC_START
TABLE1 .byte 0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6,0xf5,0xf4,0xf3,0xf2,0xf1,0xf0
TABLE1_ST .word TABLE1_LOC_START
RESET mov.w #0280h,SP
mov.w #WDTPW+WDTHOLD,&WDTCTL ; stop watchdog timer
mov &TABLE1_ST, R10
mov #0xf2, R11
mov #0x08, R12
again inc R10
cmp 0(R10), R11
je found
dec R12
jz again
found mov R10, &f2Address
endProgram jmp endProgram
In an attempt to solve this problem I changed the 'je' to 'jeq' and I added 'mainLoop' to the code. After my modifications I had this code:
.label TABLE1_LOC_START
TABLE1 .byte 0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6,0xf5,0xf4,0xf3,0xf2,0xf1,0xf0
TABLE1_ST .word TABLE1_LOC_START
mainLoop mov &TABLE1_ST, R10
mov #0xf2, R11
mov #0x08, R12
again inc R10
cmp R10, R11
jeq found
dec R12
jnz again
found mov R10, &f2Address
endProgram jmp endProgram
When I step through it, R12 eventually decrements to zero. Once it does, it means that the value of 0xf2 wasn't found, so it should place a 0x00 in the 'f2Address'. But instead of placing a zero there, it simply keeps on moving through the instructions without changing/adding any values anywhere.
I am not quite sure what to do or where to go next from here. It is using CodeComposer on the MSP430.
Figured it out:
mainLoop mov &TABLE1_ST, R10
mov #0xf2, R11
mov #0x10, R12
again inc R10
cmp 0(R10), R11
jeq found
dec R12
jnz again
mov #0x00, &f2Address
found mov R10, &f2Address
endProgram jmp endProgram
I made an bubble sort program in C, and checked its assembly listing file. But I cannot get where the for loops are. Could you let me know where are the for loops and if statement?
#include<stdio.h>
int main()
{
int arr[5]={2,4,5,6,1};
int i,j,tmp;
for(i=0;i<5;i++)
{
for(j=0;j<4;j++)
{
if(arr[j]>arr[j+1])
{
tmp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=tmp;
}
}
}
for(i=0;i<5;i++){
printf(" %d",arr[i]);
}
printf("\n");
return 0;
}
And here is assembly listing file.
; generated by ARM C Compiler, ADS1.2 [Build 848]
; commandline [-O1 -browseinfo "0xff
" -S -g+ -fk -J:cw:]
CODE32
AREA ||.text||, CODE, READONLY
main PROC
|L1.0|
STMFD sp!,{r4,lr}
SUB sp,sp,#0x18
MOV r2,#0x14
LDR r1,|L1.148|
ADD r0,sp,#4
BL __rt_memcpy_w
MOV r12,#0
|L1.28|
MOV r0,#0
|L1.32|
ADD r1,sp,#4
ADD r2,sp,#4
ADD r3,r2,r0,LSL #2
LDR r1,[r1,r0,LSL #2]
LDR r2,[r3,#4]
CMP r1,r2
BLE |L1.72|
ADD lr,sp,#4
STR r2,[lr,r0,LSL #2]
STR r1,[r3,#4]
|L1.72|
ADD r0,r0,#1
CMP r0,#4
BLT |L1.32|
ADD r12,r12,#1
CMP r12,#5
BLT |L1.28|
MOV r4,#0
|L1.100|
ADD r0,sp,#4
LDR r1,[r0,r4,LSL #2]
ADR r0,|L1.152|
BL _printf
ADD r4,r4,#1
CMP r4,#5
BLT |L1.100|
ADR r0,|L1.160|
BL _printf
MOV r0,#0
ADD sp,sp,#0x18
LDMFD sp!,{r4,pc}
|L1.148|
DCD ||.constdata$1||
|L1.152|
DCB " %d"
DCB "\0\0\0\0"
|L1.160|
DCB "\n\0\0\0"
ENDP
AREA ||.constdata||, DATA, READONLY, ALIGN=2
||.constdata$1||
DCD 0x00000002
DCD 0x00000004
DCD 0x00000005
DCD 0x00000006
DCD 0x00000001
EXPORT main
IMPORT _main
IMPORT __main
IMPORT _printf
IMPORT __rt_memcpy_w
IMPORT ||Lib$$Request$$armlib||, WEAK
KEEP
Here you go. If you just looked for CMP and the constants, you should have been able to find them:
LDR r1,[r1,r0,LSL #2] ; r1 = arr[j]
LDR r2,[r3,#4] ; r2 = arr[j+1]
CMP r1,r2 ; arr[j] <= arr[j+1]
BLE |L1.72| ; jump if yes
ADD lr,sp,#4 ; arr
STR r2,[lr,r0,LSL #2] ; arr[j] = arr[j+1]
STR r1,[r3,#4] ; arr[j+1] = arr[j]
|L1.72|
ADD r0,r0,#1 ; j++
CMP r0,#4 ; j < 4
BLT |L1.32| ; jump to inner loop if yes
ADD r12,r12,#1 ; i++
CMP r12,#5 ; i < 5
BLT |L1.28| ; jump to outer loop if yes
I have the following code, where I am trying to add a new interrupt (int 0x21) for 16-bit mode of x86:
void main()
{
char* str = "Enter the string!\n\r";
makeInterrupt21();
interrupt(0x21,0,str,0,0);
}
The interrupt and the makeInterrupt21 functions are written in assembly. The interrupt function simply calls the interrupt number as given by the first argument with rest of the arguments determining the valuses of ax, bx, cx and dx registers respectively.
The makeInterrupt21 function sets the entry for the jump address of interrupt 0x21.
.global _interrupt
_interrupt:
push bp
mov bp, sp
push si
push ds
mov ax, #0x100
mov ds, ax
mov ax, [bp + 0x4]
mov si, #intr
mov [si + 1], al
pop ds
mov ax, [bp + 0x6]
mov bx, [bp + 0x8]
mov cx, [bp + 0xa]
mov dx, [bp + 0xc]
intr: int #0x0
pop si
pop bp
ret
.global _makeInterrupt21
_makeInterrupt21:
push bp
mov bp, sp
push es
mov ax, #0x0
mov es, ax
mov bx, #0x84
mov ax, #interrupt21ServiceHandler
eseg
mov [bx], ax
eseg
mov [bx + 0x2], ds
pop es
pop bp
ret
.extern _handleInterrupt21
interrupt21ServiceHandler:
push dx
push cx
push bx
push ax
call _handleInterrupt21
ret
The handleInterrupt21 is the interrupt handler function for the interrupt 0x21 and is written in C:
void handleInterrupt21(int ax, int bx, int cx, int dx)
{
char* line;
line = bx;
switch (ax)
{
case 0x0:
printString(line);
break;
default:
printString("Error invalid arguments!");
break;
}
}
The printString function prints the string starting at the address given by the argument given to it:
int printString(char* string)
{
int i = 0;
while (*(string + i) != '\0')
{
char al = *(string + i);
char ah = 0xe;
int ax = ah * 256 + al;
interrupt(0x10,ax,0,0,0);
i++;
}
return i;
}
When I run this code on QEmu, I get into an infinite loop which prints:
Enter the string!
Enter the string!
Enter the string!
When I ran this on QEmu, I got the following error:
Program received signal SIGTRAP, Trace/breakpoint trap.
Could anyone explain why am I stuck in a loop?
EDIT:
Also please explain the meaning of breakpoint trap and why am I getting this error. I read a related question on this but I couldn't understand the answer.