writing a functional description of a c funtion

this is a project for class so please dont ask me why Im doing it this way or suggest doing it differently.

Here is the C function I am given:

unsigned strcspn(const char *s1, const char *s2)
{
    const char *s = s1;	
    const char *c;

    while(*s1)
    {
	for(c = s2; *c; c++)
        {
	     if(*s1 == *c) 
	          break;
        }
        if(*c)
	     break;
        s1++;
    }
    return s1 - s;
}

here is the assembly code that it compiles to.

	.file	"function.c"
	.text
	.align	2
	.global	strcspn
	.type	strcspn, %function
strcspn:
	@ args = 0, pretend = 0, frame = 0
	@ frame_needed = 0, uses_anonymous_args = 0
	stmfd	sp!, {r4, lr}
	mov	lr, r0
	ldrb	r0, [r0, #0]	@ zero_extendqisi2
	cmp	r0, #0
	mov	r4, r1
	movne	ip, lr
	ldrneb	r1, [r1, #0]	@ zero_extendqisi2
	ldmeqfd	sp!, {r4, pc}
.L5:
	cmp	r1, #0
	beq	.L9
	cmp	r1, r0
	beq	.L12
	mov	r3, r4
	b	.L7
.L6:
	cmp	r2, r0
	beq	.L15
.L7:
	ldrb	r2, [r3, #1]	@ zero_extendqisi2
	cmp	r2, #0
	add	r3, r3, #1
	bne	.L6
.L9:
	ldrb	r0, [ip, #1]!	@ zero_extendqisi2
	cmp	r0, #0
	bne	.L5
.L15:
	rsb	r0, lr, ip
	ldmfd	sp!, {r4, pc}
.L12:
	rsb	r0, lr, ip
	ldmfd	sp!, {r4, pc}
	.size	strcspn, .-strcspn
	.ident	"GCC: (GNU) 4.1.2"

here is my question. The third instruction is

	ldrb	r0, [r0, #0]	@ zero_extendqisi2

I belive that this loads the first character in s1 into r0. Was s1 passed into this function in r0? Or would I say the address of the first character in s1 was passed in in r0? Now what happens to r0? What was the purpose of this? As far as I can see all this did was cut off the next three characters in s1.

Look up the “ARM procedure call standard”.

Basically the first 4 arguments to a function are passed in r0-r3, and any remaining arguments are passed on the stack. r0-r3, r12, and r14 are free to use in your function (i.e. the caller assumes they contain garbage afterward), although r14 contains your return address, so you’ll want to keep track of that. If you need more registers, you can push them onto the stack and pop them at the end so the caller will never know.

So in your function, s1 goes in r0, and s2 in r1. That load instruction is loading the first character of the string into r0, which does overwrite the original pointer. But before that, it copies the pointer into r14 (mov lr, r0), so it’s not gone forever.

But just FYI, it is perfectly legal to overwrite the argument entirely if you know you’re not going to need it again before the end of the function.

Sorry to resurrect a dead thread, but this was the best Google result for the same question 3 years later, and I wanted other searchers to have better luck.

lusher00:
this is a project for class so please dont ask me why Im doing it this way or suggest doing it differently.

Hey, I just had the same project! Was this for [[this](http://claymore.engineer.gvsu.edu/~steriana/courses/424) class?

To any future Googlenauts, the answer is that the @ zero_extendqisi2 directive tells the linker to store this in a word-aligned byte value.

In addition, using the arm-none-eabi-gcc compiler for the v7-M Cortex-M3, the commented assembly is:

strcspn:;Preserve registers which cannot be changed between function calls and copy s1.
5)	push {r4, r5, lr}	;Entry point; push registers to save onto stack.
6)	mov	 r3, r0	;Move r0[was s1, now s] to r3[s1]
7)	b    .L2		;Branch to .L2
.L4: 	;Check *s1 != *s2 and increment c_off, the difference between c and s2.
8)	adds r2, r2, #1	;Add 1 to r2[c_off]
9)	cmp	 r4, r5	;Compare r4[*s1] to r5[*s2 + c_off]
10)	beq	 .L3		;Branch to .L3 if r4[*s1] == r5[*s2]; or go on to .L6
.L6:	;Load s2 offset by c and check it for null.
				;Load contents of r1[s2][offset by r2[c_off]] into r5[*s2]
11)	ldrb r5, [r1, r2]	@ zero_extendqisi2 ;zero extend the load (write LSByte)
12)	cmp	 r5, #0	;Compare r5[*s2] to 0[null].
13)	bne	 .L4		;Branch to L4 if the comparison *s2 == 0 was false
14)	b	 .L11		;Otherwise branch to .L11
.L2:	;Load s1 and check it for null, also set c_off to 0.
				;Load contents of r3[s1][offset by 0] into r4[*s1]
15)	ldrb r4, [r3, #0]	@ zero_extendqisi2	;zero extend the load (write LSByte)
16)	cbz  r4, .L3		;Branch to .L3 if r4[*s1] is 0[null].
17)	movs r2, #0		;Reset r2[c_off] to 0.
18)	b	 .L6		;Branch to .L6
.L3:	;Restore preserved registers, and return s1 – s.
19)	subs r0, r3, r0	;Subtract r3[s1] from r0[s]
20)	pop {r4, r5, pc}	;Restore saved registers and branch to the saved LR.
.L11:	;Increment s1 and go to step 2.
21)	adds r3, r3, #1	;Add one to r3[s1]
22)	b	 .L2		;Branch to .L2

Be aware that this is a fairly new instruction set, and so this code is far from optimal. Take, for instance, .L11. Why is it there at all?](http://claymore.engineer.gvsu.edu/~steriana/courses/424)