Here is an arm assembly code for factorial function (along with the c code).i am a bit confused with the stmfd and ldmfd instructions.what are they exactly doing in this program? what does the exclamation mark do? why is label .L2 being loaded into r0? i kno that stmfd and ldmfd are used to store and load multiple registers in full descending mode but what are they doing with fp,ip,lr,pc in this code?

.file	"factorial.c"
	.text
	.align	2
	.global	factorial
	.type	factorial, %function
factorial:
	@ args = 0, pretend = 0, frame = 8
	@ frame_needed = 1, uses_anonymous_args = 0
	mov	ip, sp
	stmfd	sp!, {fp, ip, lr, pc}
	sub	fp, ip, #4
	sub	sp, sp, #8
	str	r0, [fp, #-16]
	ldr	r3, [fp, #-16]
	cmp	r3, #1
	bne	.L2
	mov	r3, #1
	str	r3, [fp, #-20]
	b	.L1
.L2:
	ldr	r3, [fp, #-16]
	sub	r3, r3, #1
	mov	r0, r3
	bl	factorial
	mov	r3, r0
	ldr	r2, [fp, #-16]
	mul	r3, r2, r3
	str	r3, [fp, #-20]
.L1:
	ldr	r0, [fp, #-20]
	sub	sp, fp, #12
	ldmfd	sp, {fp, sp, pc}
	.size	factorial, .-factorial
	.section	.rodata
	.align	2
.LC0:
	.ascii	"%d\n\000"
	.text
	.align	2
	.global	main
	.type	main, %function
main:
	@ args = 0, pretend = 0, frame = 4
	@ frame_needed = 1, uses_anonymous_args = 0
	mov	ip, sp
	stmfd	sp!, {fp, ip, lr, pc}
	sub	fp, ip, #4
	sub	sp, sp, #4
	mov	r0, #3
	bl	factorial
	mov	r3, r0
	str	r3, [fp, #-16]
	ldr	r0, .L4
	ldr	r1, [fp, #-16]
	bl	printf
	mov	r0, r3
	ldmfd	sp, {r3, fp, sp, pc}
.L5:
	.align	2
.L4:
	.word	.LC0
	.size	main, .-main
	.ident	"GCC: (GNU) 3.4.3"

Dani AI

Generated

Short answer for : stmfd/ldmfd are just the ARM “push/pop multiple” pair in full‑descending form, and the exclamation mark means “write back” (i.e. update the base register). The compiler saves fp/ip/lr/pc to build a stable frame so the function can reference arguments and locals with fixed offsets; it later restores registers and returns by loading the saved return address into PC.

What each name does here

  • fp (r11): frame pointer — saved and restored so the function can use fixed offsets for locals/args.
  • ip (r12): intra-procedure scratch — here it is used to stash the original SP so fp can be computed relative to it.
  • lr (r14): link register — holds the return address set by bl; LDM restores it into PC to return.
  • pc (r15): program counter — the prologue stores a PC word so fp points at a fixed slot in the frame. The epilogue actually loads PC from the saved LR slot to branch back; the saved PC word ends up as part of the frame layout (not the value used for the return).

Frame layout and restore (conceptual): mov ip,sp saves original SP into ip; the STMFD with write‑back pushes saved registers and moves SP down; fp is then set relative to that saved area so locals live at negative offsets from fp. Before return the stack pointer is reset to the start of that saved area and LDMFD restores fp and sp and then loads PC (causing the branch back).

About loading labels into a register: when you saw a label being “loaded into r2” in another example, that was a PC‑relative literal load (assembler pseudo like ldr rX, =label) which places the address/value in a literal pool and reads it into the register. That yields an address or constant (used for data or indirect branches), it does not by itself perform a branch.

Note: reading PC as a general register returns the pipelined PC value (ARM state typically PC+8), so stored PC values reflect that pipeline offset.

the c code:

#include <stdio.h>

int factorial(int n) {
	if(n == 1) return 1;
	return n * factorial(n-1);
}
int main() {
	int val = factorial(3);
	printf("%d\n",val);
}

ok i am sorry, label .L2 is not being loaded into register r2 in this case but i saw an example where it does.what does that do?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.