return values in assembly subroutine
return values in assembly subroutine
For those who have decompiled allegrex assembly code before, i got another question for you, but i think it's a pretty general assembly code question tho =P
$v0 and $v1 are the return value registers, but why would you ever want to use both of them for the return value? the only instance i can think of is when you want to return a 64bit long double value, are there any other instances you will need to make use of both registers? and when determining the return value, if i see both $v0 and $v1 are used as a target register for some instructions, can i say that the subroutine is using both of them as return values for sure (that is, can i assume that the subroutine will not use any v registers for temp variable if the subroutine isn't returning any values)?
also, i came across something that doesn't make sense to me at the entry point of a subroutine:
addiu $sp, $sp, -4144
sw $ra, 4128($sp)
jal foo
lw $ra, 4128($sp)
jr $ra
addiu $sp, $sp, 4144
how come it reserves so many stack space but only to store a single return address register?!?!?
assembly isn't easy to learn, and i appreciate any related helps.
$v0 and $v1 are the return value registers, but why would you ever want to use both of them for the return value? the only instance i can think of is when you want to return a 64bit long double value, are there any other instances you will need to make use of both registers? and when determining the return value, if i see both $v0 and $v1 are used as a target register for some instructions, can i say that the subroutine is using both of them as return values for sure (that is, can i assume that the subroutine will not use any v registers for temp variable if the subroutine isn't returning any values)?
also, i came across something that doesn't make sense to me at the entry point of a subroutine:
addiu $sp, $sp, -4144
sw $ra, 4128($sp)
jal foo
lw $ra, 4128($sp)
jr $ra
addiu $sp, $sp, 4144
how come it reserves so many stack space but only to store a single return address register?!?!?
assembly isn't easy to learn, and i appreciate any related helps.
I wouldn't assume it's doing anything clever. It could just be unoptimised (or poorly optimised) code generated by the compiler:
or even
Or maybe they were occassionally stomping on their stack in foo and 'fixed' it by allocating a chunk of unused memory on the stack? :)
Code: Select all
void blah()
{
char buf[4140];
//sprintf( buf, "in blah, about to call foo: %s", some_other_stuff );
//Display( buf );
foo();
}
Code: Select all
void Blah()
{
void * buf = alloca(4140);
// Did something with buf, commented out
foo();
}
A structure that fits in both regs will be returned that way as well.$v0 and $v1 are the return value registers, but why would you ever want to use both of them for the return value? the only instance i can think of is when you want to return a 64bit long double value, are there any other instances you will need to make use of both registers?
like...? i think a pointer is enough for any kind of structuresJ.F. wrote:A structure that fits in both regs will be returned that way as well.$v0 and $v1 are the return value registers, but why would you ever want to use both of them for the return value? the only instance i can think of is when you want to return a 64bit long double value, are there any other instances you will need to make use of both registers?
Like obviously simple structures... ones less than or equal to 64 bits. You could do it via pointer as well, but gcc does allow the passing of structures directly in paired registers on certain platforms - ones with lots of regs, like RISC platforms.serige wrote:like...? i think a pointer is enough for any kind of structuresJ.F. wrote:A structure that fits in both regs will be returned that way as well.$v0 and $v1 are the return value registers, but why would you ever want to use both of them for the return value? the only instance i can think of is when you want to return a 64bit long double value, are there any other instances you will need to make use of both registers?
come across another weird place:
here is the function call:
; ======================================================
; Subroutine sub_0013AD58 - Address 0x0013AD58
sub_0013AD58: ; Refs: 0x0013AC8C 0x0013ACD0
0x0013AD58: 0x27BDFFE0 '...'' - addiu $sp, $sp, -32
0x0013AD5C: 0xAFB3000C '....' - sw $s3, 12($sp)
0x0013AD60: 0x00C09821 '!...' - move $s3, $a2
0x0013AD64: 0xAFB10004 '....' - sw $s1, 4($sp)
0x0013AD68: 0x00A08821 '!...' - move $s1, $a1
0x0013AD6C: 0x24050012 '...$' - li $a1, 18
0x0013AD70: 0xAFB00000 '....' - sw $s0, 0($sp)
0x0013AD74: 0x00808021 '!...' - move $s0, $a0
0x0013AD78: 0x00E02021 '! ..' - move $a0, $a3
0x0013AD7C: 0xAFB20008 '....' - sw $s2, 8($sp)
0x0013AD80: 0xAFBF0010 '....' - sw $ra, 16($sp)
0x0013AD84: 0x0C04EBFB '....' - jal sub_0013AFEC <------
0x0013AD88: 0x00E09021 '!...' - move $s2, $a3
0x0013AD8C: 0x0233182B '+.3.' - sltu $v1, $s1, $s3
....
and here is the function definition:
; ======================================================
; Subroutine sub_0013AFEC - Address 0x0013AFEC
sub_0013AFEC: ; Refs: 0x0013AD84 0x0013AEA0
0x0013AFEC: 0x24031000 '...$' - li $v1, 4096
0x0013AFF0: 0x00651023 '#.e.' - subu $v0, $v1, $a1
0x0013AFF4: 0x00805021 '!P..' - move $t2, $a0
0x0013AFF8: 0x18400007 '..@.' - blez $v0, loc_0013B018
0x0013AFFC: 0x00005821 '!X..' - move $t3, $zr
0x0013B000: 0x00402021 '! @.' - move $a0, $v0
loc_0013B004: ; Refs: 0x0013B010
0x0013B004: 0x014B1021 '!.K.' - addu $v0, $t2, $t3
0x0013B008: 0x256B0001 '..k%' - addiu $t3, $t3, 1
0x0013B00C: 0x0164282A '*(d.' - slt $a1, $t3, $a0
0x0013B010: 0x14A0FFFC '....' - bnez $a1, loc_0013B004
0x0013B014: 0xA0400000 '..@.' - sb $zr, 0($v0)
loc_0013B018: ; Refs: 0x0013AFF8
0x0013B018: 0x00004821 '!H..' - move $t1, $zr
0x0013B01C: 0x00005821 '!X..' - move $t3, $zr
loc_0013B020: ; Refs: 0x0013B084
0x0013B020: 0x252D0001 '..-%' - addiu $t5, $t1, 1
0x0013B024: 0x25AC0001 '...%' - addiu $t4, $t5, 1
0x0013B028: 0x25840001 '...%' - addiu $a0, $t4, 1
0x0013B02C: 0x24820001 '...$' - addiu $v0, $a0, 1
0x0013B030: 0x24450001 '..E$' - addiu $a1, $v0, 1
0x0013B034: 0x24A70001 '...$' - addiu $a3, $a1, 1
0x0013B038: 0x0149C821 '!.I.' - addu $t9, $t2, $t1
0x0013B03C: 0x014D4021 '!@M.' - addu $t0, $t2, $t5
0x0013B040: 0x014C3021 '!0L.' - addu $a2, $t2, $t4
0x0013B044: 0x0144C021 '!.D.' - addu $t8, $t2, $a0
0x0013B048: 0x01427821 '!xB.' - addu $t7, $t2, $v0
0x0013B04C: 0x01457021 '!pE.' - addu $t6, $t2, $a1
0x0013B050: 0x01476821 '!hG.' - addu $t5, $t2, $a3
0x0013B054: 0xA32B0000 '..+.' - sb $t3, 0($t9)
0x0013B058: 0x24E30001 '...$' - addiu $v1, $a3, 1
0x0013B05C: 0x01436021 '!`C.' - addu $t4, $t2, $v1
0x0013B060: 0xA1000000 '....' - sb $zr, 0($t0)
0x0013B064: 0x24690001 '..i$' - addiu $t1, $v1, 1
0x0013B068: 0xA0CB0000 '....' - sb $t3, 0($a2)
0x0013B06C: 0xA3000000 '....' - sb $zr, 0($t8)
0x0013B070: 0xA1EB0000 '....' - sb $t3, 0($t7)
0x0013B074: 0xA1C00000 '....' - sb $zr, 0($t6)
0x0013B078: 0xA1AB0000 '....' - sb $t3, 0($t5)
0x0013B07C: 0x256B0001 '..k%' - addiu $t3, $t3, 1
0x0013B080: 0x29640100 '..d)' - slti $a0, $t3, 256
0x0013B084: 0x1480FFE6 '....' - bnez $a0, loc_0013B020
0x0013B088: 0xA1800000 '....' - sb $zr, 0($t4)
0x0013B08C: 0x24090800 '...$' - li $t1, 2048
0x0013B090: 0x00005821 '!X..' - move $t3, $zr
0x0013B094: 0x240CFFFF '...$' - li $t4, -1
loc_0013B098: ; Refs: 0x0013B0F0
0x0013B098: 0x252F0001 '../%' - addiu $t7, $t1, 1
0x0013B09C: 0x25EE0001 '...%' - addiu $t6, $t7, 1
0x0013B0A0: 0x25CD0001 '...%' - addiu $t5, $t6, 1
0x0013B0A4: 0x25A40001 '...%' - addiu $a0, $t5, 1
0x0013B0A8: 0x24870001 '...$' - addiu $a3, $a0, 1
0x0013B0AC: 0x24E80001 '...$' - addiu $t0, $a3, 1
0x0013B0B0: 0x01491021 '!.I.' - addu $v0, $t2, $t1
0x0013B0B4: 0x014F3021 '!0O.' - addu $a2, $t2, $t7
0x0013B0B8: 0x014E2821 '!(N.' - addu $a1, $t2, $t6
0x0013B0BC: 0x014DC821 '!.M.' - addu $t9, $t2, $t5
0x0013B0C0: 0x01441821 '!.D.' - addu $v1, $t2, $a0
0x0013B0C4: 0x0147C021 '!.G.' - addu $t8, $t2, $a3
0x0013B0C8: 0x01487821 '!xH.' - addu $t7, $t2, $t0
0x0013B0CC: 0xA04B0000 '..K.' - sb $t3, 0($v0)
0x0013B0D0: 0xA0CC0000 '....' - sb $t4, 0($a2)
0x0013B0D4: 0xA0AB0000 '....' - sb $t3, 0($a1)
0x0013B0D8: 0xA32C0000 '..,.' - sb $t4, 0($t9)
0x0013B0DC: 0xA06B0000 '..k.' - sb $t3, 0($v1)
0x0013B0E0: 0xA30C0000 '....' - sb $t4, 0($t8)
0x0013B0E4: 0xA1EB0000 '....' - sb $t3, 0($t7)
0x0013B0E8: 0x256B0001 '..k%' - addiu $t3, $t3, 1
0x0013B0EC: 0x296E0100 '..n)' - slti $t6, $t3, 256
0x0013B0F0: 0x15C0FFE9 '....' - bnez $t6, loc_0013B098
0x0013B0F4: 0x25090001 '...%' - addiu $t1, $t0, 1
0x0013B0F8: 0x03E00008 '....' - jr $ra
0x0013B0FC: 0x00000000 '....' - nop
0x0013B100: 0x3C02004C 'L..<' - lui $v0, 0x4C
; Data ref 0x004BF8F7 ... 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x0013B104: 0x9044F8F7 '..D.' - lbu $a0, -1801($v0)
0x0013B108: 0x03E00008 '....' - jr $ra
0x0013B10C: 0x308200FF '...0' - andi $v0, $a0, 0xFF
//end of Subroutine sub_0013AFEC
as you can see $ra has not been modified in any way before the function returns, but it has 2 'jr $ra' instructions at the end!
i am assuming the original c code would look something like this:
sub_0013AFEC(){
...
...
...
t1 = t0 + 1; //0x0013B0F4
return;
v0 = 0x004C0000;
a0 = v0[-1801];
v0 = a0 & 0xFF;
return;
}
and of course, the code after the first return would never be executed. can anyone justify this? or the compiler is doing something fancy that i somehow fail to notice?
here is the function call:
; ======================================================
; Subroutine sub_0013AD58 - Address 0x0013AD58
sub_0013AD58: ; Refs: 0x0013AC8C 0x0013ACD0
0x0013AD58: 0x27BDFFE0 '...'' - addiu $sp, $sp, -32
0x0013AD5C: 0xAFB3000C '....' - sw $s3, 12($sp)
0x0013AD60: 0x00C09821 '!...' - move $s3, $a2
0x0013AD64: 0xAFB10004 '....' - sw $s1, 4($sp)
0x0013AD68: 0x00A08821 '!...' - move $s1, $a1
0x0013AD6C: 0x24050012 '...$' - li $a1, 18
0x0013AD70: 0xAFB00000 '....' - sw $s0, 0($sp)
0x0013AD74: 0x00808021 '!...' - move $s0, $a0
0x0013AD78: 0x00E02021 '! ..' - move $a0, $a3
0x0013AD7C: 0xAFB20008 '....' - sw $s2, 8($sp)
0x0013AD80: 0xAFBF0010 '....' - sw $ra, 16($sp)
0x0013AD84: 0x0C04EBFB '....' - jal sub_0013AFEC <------
0x0013AD88: 0x00E09021 '!...' - move $s2, $a3
0x0013AD8C: 0x0233182B '+.3.' - sltu $v1, $s1, $s3
....
and here is the function definition:
; ======================================================
; Subroutine sub_0013AFEC - Address 0x0013AFEC
sub_0013AFEC: ; Refs: 0x0013AD84 0x0013AEA0
0x0013AFEC: 0x24031000 '...$' - li $v1, 4096
0x0013AFF0: 0x00651023 '#.e.' - subu $v0, $v1, $a1
0x0013AFF4: 0x00805021 '!P..' - move $t2, $a0
0x0013AFF8: 0x18400007 '..@.' - blez $v0, loc_0013B018
0x0013AFFC: 0x00005821 '!X..' - move $t3, $zr
0x0013B000: 0x00402021 '! @.' - move $a0, $v0
loc_0013B004: ; Refs: 0x0013B010
0x0013B004: 0x014B1021 '!.K.' - addu $v0, $t2, $t3
0x0013B008: 0x256B0001 '..k%' - addiu $t3, $t3, 1
0x0013B00C: 0x0164282A '*(d.' - slt $a1, $t3, $a0
0x0013B010: 0x14A0FFFC '....' - bnez $a1, loc_0013B004
0x0013B014: 0xA0400000 '..@.' - sb $zr, 0($v0)
loc_0013B018: ; Refs: 0x0013AFF8
0x0013B018: 0x00004821 '!H..' - move $t1, $zr
0x0013B01C: 0x00005821 '!X..' - move $t3, $zr
loc_0013B020: ; Refs: 0x0013B084
0x0013B020: 0x252D0001 '..-%' - addiu $t5, $t1, 1
0x0013B024: 0x25AC0001 '...%' - addiu $t4, $t5, 1
0x0013B028: 0x25840001 '...%' - addiu $a0, $t4, 1
0x0013B02C: 0x24820001 '...$' - addiu $v0, $a0, 1
0x0013B030: 0x24450001 '..E$' - addiu $a1, $v0, 1
0x0013B034: 0x24A70001 '...$' - addiu $a3, $a1, 1
0x0013B038: 0x0149C821 '!.I.' - addu $t9, $t2, $t1
0x0013B03C: 0x014D4021 '!@M.' - addu $t0, $t2, $t5
0x0013B040: 0x014C3021 '!0L.' - addu $a2, $t2, $t4
0x0013B044: 0x0144C021 '!.D.' - addu $t8, $t2, $a0
0x0013B048: 0x01427821 '!xB.' - addu $t7, $t2, $v0
0x0013B04C: 0x01457021 '!pE.' - addu $t6, $t2, $a1
0x0013B050: 0x01476821 '!hG.' - addu $t5, $t2, $a3
0x0013B054: 0xA32B0000 '..+.' - sb $t3, 0($t9)
0x0013B058: 0x24E30001 '...$' - addiu $v1, $a3, 1
0x0013B05C: 0x01436021 '!`C.' - addu $t4, $t2, $v1
0x0013B060: 0xA1000000 '....' - sb $zr, 0($t0)
0x0013B064: 0x24690001 '..i$' - addiu $t1, $v1, 1
0x0013B068: 0xA0CB0000 '....' - sb $t3, 0($a2)
0x0013B06C: 0xA3000000 '....' - sb $zr, 0($t8)
0x0013B070: 0xA1EB0000 '....' - sb $t3, 0($t7)
0x0013B074: 0xA1C00000 '....' - sb $zr, 0($t6)
0x0013B078: 0xA1AB0000 '....' - sb $t3, 0($t5)
0x0013B07C: 0x256B0001 '..k%' - addiu $t3, $t3, 1
0x0013B080: 0x29640100 '..d)' - slti $a0, $t3, 256
0x0013B084: 0x1480FFE6 '....' - bnez $a0, loc_0013B020
0x0013B088: 0xA1800000 '....' - sb $zr, 0($t4)
0x0013B08C: 0x24090800 '...$' - li $t1, 2048
0x0013B090: 0x00005821 '!X..' - move $t3, $zr
0x0013B094: 0x240CFFFF '...$' - li $t4, -1
loc_0013B098: ; Refs: 0x0013B0F0
0x0013B098: 0x252F0001 '../%' - addiu $t7, $t1, 1
0x0013B09C: 0x25EE0001 '...%' - addiu $t6, $t7, 1
0x0013B0A0: 0x25CD0001 '...%' - addiu $t5, $t6, 1
0x0013B0A4: 0x25A40001 '...%' - addiu $a0, $t5, 1
0x0013B0A8: 0x24870001 '...$' - addiu $a3, $a0, 1
0x0013B0AC: 0x24E80001 '...$' - addiu $t0, $a3, 1
0x0013B0B0: 0x01491021 '!.I.' - addu $v0, $t2, $t1
0x0013B0B4: 0x014F3021 '!0O.' - addu $a2, $t2, $t7
0x0013B0B8: 0x014E2821 '!(N.' - addu $a1, $t2, $t6
0x0013B0BC: 0x014DC821 '!.M.' - addu $t9, $t2, $t5
0x0013B0C0: 0x01441821 '!.D.' - addu $v1, $t2, $a0
0x0013B0C4: 0x0147C021 '!.G.' - addu $t8, $t2, $a3
0x0013B0C8: 0x01487821 '!xH.' - addu $t7, $t2, $t0
0x0013B0CC: 0xA04B0000 '..K.' - sb $t3, 0($v0)
0x0013B0D0: 0xA0CC0000 '....' - sb $t4, 0($a2)
0x0013B0D4: 0xA0AB0000 '....' - sb $t3, 0($a1)
0x0013B0D8: 0xA32C0000 '..,.' - sb $t4, 0($t9)
0x0013B0DC: 0xA06B0000 '..k.' - sb $t3, 0($v1)
0x0013B0E0: 0xA30C0000 '....' - sb $t4, 0($t8)
0x0013B0E4: 0xA1EB0000 '....' - sb $t3, 0($t7)
0x0013B0E8: 0x256B0001 '..k%' - addiu $t3, $t3, 1
0x0013B0EC: 0x296E0100 '..n)' - slti $t6, $t3, 256
0x0013B0F0: 0x15C0FFE9 '....' - bnez $t6, loc_0013B098
0x0013B0F4: 0x25090001 '...%' - addiu $t1, $t0, 1
0x0013B0F8: 0x03E00008 '....' - jr $ra
0x0013B0FC: 0x00000000 '....' - nop
0x0013B100: 0x3C02004C 'L..<' - lui $v0, 0x4C
; Data ref 0x004BF8F7 ... 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x0013B104: 0x9044F8F7 '..D.' - lbu $a0, -1801($v0)
0x0013B108: 0x03E00008 '....' - jr $ra
0x0013B10C: 0x308200FF '...0' - andi $v0, $a0, 0xFF
//end of Subroutine sub_0013AFEC
as you can see $ra has not been modified in any way before the function returns, but it has 2 'jr $ra' instructions at the end!
i am assuming the original c code would look something like this:
sub_0013AFEC(){
...
...
...
t1 = t0 + 1; //0x0013B0F4
return;
v0 = 0x004C0000;
a0 = v0[-1801];
v0 = a0 & 0xFF;
return;
}
and of course, the code after the first return would never be executed. can anyone justify this? or the compiler is doing something fancy that i somehow fail to notice?
13B100 seems to be other function.
I don't know which disassembler you are using but be careful, for example some dissasemblers like prxtool only detect the begin of a function when they are called, when there is a jal.
But you won't see the start of functions that are called through pointers, or that are passed to kernel functions as parameters (for example, the thread function for sceKernelCreateThread).
Anyways there must be a reference to the function. Just look for "b100" and you may find the reference. If it is not referenced, then it is a dead function, a function that the programmer implemented but didn't use.
I don't know which disassembler you are using but be careful, for example some dissasemblers like prxtool only detect the begin of a function when they are called, when there is a jal.
But you won't see the start of functions that are called through pointers, or that are passed to kernel functions as parameters (for example, the thread function for sceKernelCreateThread).
Anyways there must be a reference to the function. Just look for "b100" and you may find the reference. If it is not referenced, then it is a dead function, a function that the programmer implemented but didn't use.
it wouldn't work for B100 as its a big file and there are 4645 occurrences come out when i do the search. so its almost impossible to find out.moonlight wrote:search B100, as the reference is probably splitted between 0013 and B100 ;)serige wrote:yeah, i am using prxtool, and i have searched through the whole program (using '0013B100') but didn't see any reference pointing at that location or anywhere near there...
maybe you can suggest a better tool?