Suppose a label called L1. On MIPS, one can easily do:
beq $t1, $t2, L1
But is there a way to do the same using indirect addressing? By that, I mean using a register that holds the address where L1 is found. I know of the jr command, but I don't see how it could be used for this purpose.
beq requires an immediate value in its 3rd argument, never a register or memory address.
According to page 55 of this manual (page 63 in the PDF), the range of beq is -128 KB to +128KB, which is exactly 4 times as much as a signed 16-bit integer can represent: -32 KB to +32 KB (since instructions are 4 bytes long, a multiplier of 4 is automatically applied).
I think jr should be able to accomplish what you want. Instead of using a register to point to memory address XX, just load the value of address XX into a register and use that to jump.
lw $t0, XX
jr $t0
Related
long long int i=57745158985; #the C code
0000000000100004: li r7,13
0000000000100008: lis r8,29153
000000000010000c: ori r8,r8,0x3349
0000000000100010: stw r7,24(rsp)
0000000000100014: stw r8,28(rsp)
0000000000100018: lfd fp0,24(rsp)
000000000010001c: stfd fp0,8(rsp)
Can anyone explain the part of after the ori instruction? Thanks in advance.
It looks like this is on a 32-bit big endian machine. I will assume i is a local variable.
Starting with these instructions...
li r7,13
lis r8,29153
ori r8,r8,0x3349
After these instructions:
r7 contains 13
r8 contains ((29153 << 16) | 0x3349)
The required value for i is 57745158985, which is equal to
(13<<32) | ((29153 << 16) | 0x3349)
Clearly this value is too big to fit in a single 32-bit register.
The next instructions are where the 64-bit local variable i is "created" on the stack.
stw r7,24(rsp)
stw r8,28(rsp)
rsp is the stack pointer for the function.
Here i is being initialized to it's initial value of 57745158985.
stw r7,24(rsp) stores the four bytes of r7 starting at an offset of 24 bytes into the stack.
stw r8,28(rsp) stores the four bytes r8 starting at an offset of 28 bytes into the stack.
So i is the 8 bytes starting from an offset of 24 on the stack.
As this is a big-endian architecture the most significant bytes are placed first in memory.
Placing the value of r7 at lower address performs acts like the (13<<32) when considering the 8 bytes as one long long int.
These next instructions load the value of i into a floating point register and save it at a different location on the stack.
lfd fp0,24(rsp)
stfd fp0,8(rsp)
These 3 are loading up two 32 bit literal values into GPRs r7 and r8
0000000000100004: li r7,13
0000000000100008: lis r8,29153
000000000010000c: ori r8,r8,0x3349
These two are storing the two 32 bit values out consecutive 32 bit memory locations pointed to by rsp (which is the stack pointer == r1) + 24
0000000000100010: stw r7,24(rsp)
0000000000100014: stw r8,28(rsp)
This is a 64 bit load from the same location (ie rsp + 24) into floating point register 0 (ie fp0). (you can't move GPRs to FPR directly on this processor, so you go via memory)
0000000000100018: lfd fp0,24(rsp)
This is storing the same 64 bit FPR0 out to a different offset from the stack point.
000000000010001c: stfd fp0,8(rsp)
I've been stuck on a rather simple instruction, but everything in assembly only seems simple until I try to really understand it haha.
I've paid attention to this post which clarifies some stuff but I'm still confused: Understanding intel SUB instruction
Here is a super simple situation:
Two strings are sent to function for comparison. I stripped down to keep the essentials.
function:
mov al, [rdi] ; == 0
sub al, [rsi] ; == 32
ret ; returns 224 and not -32 like I would like
I am guessing I need to check the overflow flag right after the sub instruction if it's on, then my result is negative. Or maybe the sign flag, more logically (both seem right in this case ?)
From that, I would need to subtract 256 to rax to make it -32 before returning... But it seems a little weird to me, there is got to be a cleaner way?
The 8-bit values 224 and -32 are the same on x86 and x86-64, since it uses two's complement to represent negative numbers. Subtracting 256 wouldn't help you. It's up to the caller of the function to choose to interpret the result as signed (-128 to 127, in which case it's -32), or unsigned (0 to 255, in which case it's 224). I assume you're asking this because your code that calls this function is interpreting it wrongly. This could happen if you accidentally used movzx on the result instead of movsx to extend it, or worse, if you used ax, eax, or rax without extending it first (in which case you could end up with complete garbage like 0x11223344556677e0).
I've been learning 6502 assembly using the cbm programming studio. I’m reading a book by Jim Butterfield and Richard Mansfield. Both books discuss how one can use a method (I think it was indirect addressing) to get data from a block of memory (like messages) but there isn't an example could someone provide me one please? I don't care what method is used.
It's fairly straight forward. You set ups a pair of zero page addresses to hold the address of the start of the block and then use indirect indexing by Y to access bytes within the block. The instruction LDA ($80),Y reads the bytes at $80 and $81 as a 16 bit address ($81 contains the highest 8 bits) then adds Y on, then reads the byte at the resulting address.
Note that, if you know the address in advance, you do not need to use indirect addressing, you can use absolute indexed.
The following routine demos both address modes. It copies the 10 bytes at a location specified in the X and Y registers (Y is the high byte) to the locations following $0400
stx $80 ; Store the low byte of the source address in ZP
sty $81 ; Store the high byte of the source in ZP
ldy #0 ; zero the index
loop: lda ($80),y ; Get a byte from the source
sta $0400,y ; Store it at the destination
iny ; Increment the index
cpy #10 ; Have we done 10 bytes?
bne loop ; Go round again if not
Note that there is an obvious optimisation in the above, but I'll leave that as an exercise for the reader.
Edit OK here is the obvious optimisation as per i486's comment
stx $80 ; Store the low byte of the source address in ZP
sty $81 ; Store the high byte of the source in ZP
ldy #9 ; initialise to the highest index
loop: lda ($80),y ; Get a byte from the source
sta $0400,y ; Store it at the destination
dey ; Decrement the index
bpl loop ; Go round again if index is still >= 0
I have encountered 0x55AA in 2 scenarios:
the final 2 bytes of boot sector in the legacy booting process contains 0x55AA.
the first 2 bytes of the Option ROM must be 0x55AA
So what's special about 0x55AA?
The binary version of 0x55AA is 0101010110101010. Is it because it is evenly interleaved 0 and 1? But I don't see that's a strong criteria.
0x55AA is a "signature word". It is used as the "end of sector" marker in the last 2 bytes of a 512 byte boot record. This includes MBR and it's extended boot records and in the newer GPTs protective MBR.
References:
Image from Master Boot Record - microsoft.com.
How Basic Disks and Volumes Work - microsoft.com.
There is nothing magical or mystical about that combination. Implementers needed a means by which to determine if the first sector of a device was bootable (boot signature) and that combination occurring in the last two bytes of a sector is so improbable, is why it was chosen.Similarly, SMBIOS entry point can be found scanning BIOS for _SM_ signature that must be on an segment boundary like this;
Find_SMBIOS:
push ds
push bx ; Preserve essential
push si
; Establish DS:BX to point to base of BIOS code
mov ax, 0xf000
mov ds, ax ; Segment where table lives
xor bx, bx ; Initial pointer
mov eax, '_SM_' ; Scan buffer for this signature
; Loop has maximum of 4096 interations. As table is probably at top of buffer, cycling
; though it backwards saves time. In my test bed, BOCH's 2.6.5 BIOS-bochs-latest it was
; 1,451 interations.
.L0: sub bx, 16 ; Bump pointer to previous segment
jnz .J0
; Return NULL in AX and set CF. Either AX or flag can be tested on return.
mov ax, bx
stc
jmp .Done
; Did we find signature at this page
.J0: cmp [bx], eax
jnz .L0 ; NZ, keep looking
; Calculate checksum to verify position
mov cx, 15
mov ax, cx
mov si, bx ; DS:SI = Table entry point
; Compute checksum on next 15 bytes
.L1: lodsb
add ah, al
loop .L1
or ah, ah
jnz .L0 ; Invalid, try to find another occurence
; As entry point is page aligned, we can do this to determine segment.
shr bx, 4
mov ax, ds
add ax, bx
clc ; NC, found signature
.Done:
pop si
pop bx ; Restore essential
pop ds
ret
That signature is easily identifiable in a hex dump and it fits into a 16 bit register. Where those two criteria precipitating factors, I don't know, but again, the probability of 0x5f4d535f appearing on an even 16 byte boundary is very unlikely.
I'm trying to translate the following command to Hex:
beq $s1,$t3,label
It's also given that the command address is 0x1500, and the label address is 0x1000.
So far i know that beq equals 4(hex) and the binary values of the registers.
I know that at first I need to convert to binary and then to Hex, but i can't understand what to do with the label address. Do i need to divide it by 4 to get the value?
BEQ opcode is 000100 (binary).
The instruction format for BEQ is:
OpCode|SR|DR|Offset
where
OpCode(6 bits) is 000100
SR(5 bits) is 10001 for $s1
DR(5bits) is 01011 for $t3
offset(16 bits) is a 16 bits signed offset(shifted 2 times) assuming starting PC is the following instruction after the branch, should be (0x1000 - 0x1504)>>2 = -0x141, which written in A2 compliment is 1111111010111111
You can now concatenate the bit fields and write them in hexadecimal if you wish:
0001 0010 0010 1011 1111 1110 1011 1111 which is 0x122BFEBF
[edit: added explanation of how to compute the offset]
To compute the offset you have to subtract the value of PC+4 (where PC stands for the address of the branch instruction) and the address of the target location. Then divide that address by 4 (or shift right two times). As the offset is encoded in A2 compliment, if the result of the operation is negative you have to apply A2's compliment to get the encoded value.