ARM Assembly accepting '-' - string

So my code currently converts a string into a integer. My code is currently working and functional however, i need it to accept an "-" at the beginning of the input to judge if it is a negative or not. I have no idea how to do this and i can not find any sources. I am currently passing in (test3: .asciz "-48") into register r0. and when i run in the debugger i am receiving 45. here is my code for reference.
.global stoi
.text
stoi:
push {r4,r5,r6,r8,r9,lr}
#r0 = buffer
mov r1,#0 #r1 = n = 0
mov r9,#0 #buffer counter
mov r4,#48 #0 checker
mov r5,#57 #9 checker
b 5f
5:
ldrb r3,[r0,r9] #r3 = c
b 1f
1:
cmp r3,r4 #cmp c to 0(48 in ASCII)
bge 2f
b 4f
2:
cmp r3,r5 #cmp c to 9(57 in ASCII)
ble 3f
b 4f
3:
sub r6,r3,#'0' #r6 = (c - '0')
#strb r6,[r0,r9]
add r1,r1,r1,lsl#2 #r1 = n * 10
add r1,r1,r1,lsl#0
add r1,r1,r6 #n = n * 10 + (c - '0')
add r9,r9,#1 #add to buffer
b 5b
4:
mov r0,r1
pop {r4,r5,r6,r8,r9,pc}

use the same code you're using now, and add these changes:
1) skip the '-' if it's the first char.
Right now you're stopping if a non-digit char is read, you receive 45 (in R3), it is the ascii of '-'. Afais R1 should still be 0 tho
2) At the end, add a check if the first char is a '-', and if it is, subtract r1 from 0 (since 0 - x is -x)
( 3) remove the b 1f, it's not needed ;) )

Related

Auto-vectorization of a loop shuffling 4 int elements and taking absolute differences vs. the previous arrangement

I'm trying, without succeeding, to make the Rust compiler (rustc 1.66.0) auto-vectorize the following function (without using any unsafe intrinsics):
pub fn get_transforms(s: &mut [i32]) -> u32 {
assert_eq!(s.len(), 4);
let mut transforms = 1;
while s[0] > 0 || s[1] > 0 || s[2] > 0 || s[3] > 0 {
// Calculate deltas
let d0 = s[0] - s[1];
let d1 = s[1] - s[2];
let d2 = s[2] - s[3];
let d3 = s[3] - s[0];
// Assign absolute values
s[0] = d0.abs();
s[1] = d1.abs();
s[2] = d2.abs();
s[3] = d3.abs();
transforms += 1;
}
transforms
}
My idea is to make it perform the subtractions and the abs() once (using 16 byte registers) instead of four times.
I've read that iterators might help, but I haven't found an easy way to use them here.
Compiler flags don't seem to able to help either.
Here's the link to the Compiler Explorer output I'm using as reference: https://godbolt.org/z/7sqq6bszT
As #ChayimFriedman noted in the comments, you need to add -Copt-level=3 to the command line. But additionally, you need to make sure that the boolean-expression is not evaluated lazily, i.e., use the | operator instead of || (requires parentheses around the comparisons):
while (s[0] > 0) | (s[1] > 0) | (s[2] > 0) | (s[3] > 0) {
// rest of code unmodified
Compiling this produces the following loop:
.LBB0_13:
vpshufd xmm2, xmm0, 57
vpsubd xmm0, xmm0, xmm2
vpabsd xmm0, xmm0
inc eax
vpcmpgtd xmm2, xmm0, xmm1
vmovmskps ecx, xmm2
test ecx, ecx
jne .LBB0_13
The reason why | instead of || helps the compiler is that for expressions like a || b the b expression shall not be evaluated if a is true already -- most of the time this requires a branch depending on the value of a. On the other hand, for a | b both a and b are evaluated every time. Of course, the compiler should be allowed to do any optimization under the "as-if" rule, i.e., if evaluating b does not have any side effects (and the compiler can prove that), a || b and a | b could be compiled to the same code.
N.B.: If you are sure that s[i] are never negative (which is obviously true, if the inputs are non-negative), you can replace s[i] > 0 by s[i] != 0, which will reduce the vpcmpgtd+vmovmskps+test to a single vptest.

SAS - Replace the n'th word in a string, if a certain length

I have a list of customer ids, formatted as follows:
123-456-78;
123-345-45;
12-234-345;
123-34-456;
I want to be able to find every 2-digit portion of the code and replace it with a new number. For example, "78" in the first entry, but "12" in the third entry.
Right now I'm using the scan function with a do loop to find each 2-digit section.
data work.test12;
set MyLib.customers;
do i=1 to 5;
x=scan(customer_id,i,'-');
if length(x)=2 then
do;
<??????>;
end;
output;
end;
I think regular expression will work nicely.
33 data _null_;
34 infile cards dsd dlm=';';
35 input s :$16.;
36 if _n_ eq 1 then rx = prxparse('s/(^|-)\d\d($|-)/\100\2/');
37 retain rx;
38 length new $16;
39 if prxmatch(rx,strip(s)) then new=prxchange(rx,1,strip(s));
40 put s= new=;
41 cards4;
s=123-456-78 new=123-456-00
s=123-345-45 new=123-345-00
s=12-234-345 new=00-234-345
s=123-34-456 new=123-00-456
The SCAN method can be greatly simplified and I speculate efficiency improved using CALL SCAN and SUBSTR on the left. CALL SCAN returns the position and LENGTH of the sub-string without extracting anything which you don't need.
33 data _null_;
34 infile cards dsd dlm=';';
35 input s :$16.;
36 put 'NOTE: ' s= #;
37 do i = 1 by 1 until(p eq 0);
38 call scan(s,i,p,l);
39 if l eq 2 then substr(s,p,l)='00';
40 end;
41 put s=;
42 cards4;
NOTE: s=123-456-7 s=123-456-7
NOTE: s=123-456-78 s=123-456-00
NOTE: s=123-345-45 s=123-345-00
NOTE: s=12-234-345 s=00-234-345
NOTE: s=123-34-456 s=123-00-456
Is the desired 2-digit number the same for all replacements?
You can use scan and tranwrd, but you need to ensure you don't replace the leading or trailing 2 digits of 3-digit numbers also. You can do this by padding both the old & new 2-digit number with hyphens, and by padding the whole customer_id too :
%LET NEW_NUM = 99 ; /* The number to convert all 2-digits to */
data want ;
set mylib.customers ;
do i = 1 to countw(customer_id,'-') ;
num = scan(customer_id,i,'-') ;
if length(num) = 2 then do ;
/* add leading & trailing - */
temp_customer_id = cats('-',customer_id,'-') ;
/* switch the 2-digit numbers */
tran_customer_id = tranwrd(temp_customer_id,cats('-',num,'-'),cats('-',"&NEW_NUM",'-')) ;
/* drop the leading & trailing - */
tran2_customer_id = substr(tran_customer_id,2,length(tran_customer_id)-2) ;
end ;
run ;

finding GHC assembly for a function

I'd like to identify what assembly GHC produces for a given function.
Here, for example, is some code which (should) rotate bits around in a word - it moves bit 0 to bit 12, bit 12 to 14, bit 14 back to 0 and similarly for the positions 1, 18, 13 and 6.
What's the best way to go about finding the assembly generated for rot0cw in the .S file produced by ghc -O2 -S ...?
I've read this answer, but I don't see any ..._rot0cw_closure in the assembly output.
import Data.Bits
import Data.Int (Int64)
import Text.Printf
import System.Environment
{-# INLINE maskbits #-}
-- set in word v the bits of b corresponding to the mask m
-- assume a bit in b is zero if not in the mask
maskbits v m b = (v .&. (complement m) .|. b)
{-# INLINE tb #-}
-- transfer bit i of word v to bit j of word m; assume bit j of m is 0
tb v i j m = m .|. (rotate (v .&. (bit i)) (j-i))
rot0cw :: Int64 -> Int64
rot0cw v = maskbits (maskbits v m1 b1) m2 b2
where
m1 = 0x0000005005
b1 = tb v 0 2 . tb v 2 14 . tb v 14 12 . tb v 12 0 $ 0
m2 = 0x0000002142
b2 = tb v 1 8 . tb v 8 13 . tb v 13 6 . tb v 6 1 $ 0
showBits v =
let set = [ i | i <- [0..35], testBit v i ]
in "bits set: " ++ (unwords $ map show set)
main = do
(arg0:_) <- getArgs
let v = read arg0
-- let v = 0x0000000005
let v' = rot0cw v
putStrLn $ printf "v = 0x%010x = %12d %s" v v (showBits v)
putStrLn $ printf "v' = 0x%010x = %12d %s" v' v' (showBits v')
I've read this answer, but I don't see any ..._rot0cw_closure in the assembly output.
You need to name your module. e.g. add module Main where at the beginning* to get Main_rot0cw_closure in the generated assembly.
* Strictly speaking, your module needs to export the function.
You will need to export the function rot0cw from your module, otherwise it's effectively dead code. So add something like this to the top of your module:
module Asm(rot0cw) where
The assembly it generates is rather large, if you dump the Cmm -ddump-cmm you can look at each of the proc blocks labeled with the name of the function you're interested in. The basic blocks GHC generates here roughly corresponds to a label in the resulting assembly. So for instance the entry code for rot0cw_closure maps to the following:
cB2:
if (Sp - 32 < SpLim) goto cB4;
Hp = Hp + 16;
if (Hp > HpLim) goto cB6;
I64[Sp - 16] = stg_upd_frame_info;
I64[Sp - 8] = R1;
I64[Hp - 8] = S#_con_info;
I64[Hp + 0] = 0;
I64[Sp - 24] = Hp - 7;
I64[Sp - 32] = stg_ap_p_info;
R2 = $fNumInt64_closure;
Sp = Sp - 32;
jump fromInteger_info; // [R2]
cB4: jump stg_gc_enter_1; // [R1]
cB6:
HpAlloc = 16;
goto cB4;
Which generates out to:
_cB2:
leaq -32(%rbp),%rax
cmpq %r15,%rax
jb _cB4
addq $16,%r12
cmpq 144(%r13),%r12
ja _cB6
movq $stg_upd_frame_info,-16(%rbp)
movq %rbx,-8(%rbp)
movq $S#_con_info,-8(%r12)
movq $0,0(%r12)
leaq -7(%r12),%rax
movq %rax,-24(%rbp)
movq $stg_ap_p_info,-32(%rbp)
movl $$fNumInt64_closure,%r14d
addq $-32,%rbp
jmp fromInteger_info
_cB6:
movq $16,192(%r13)
_cB4:
jmp *-16(%r13)
.size sat_info, .-sat_info
Invariably you'll get a lot of "noise" from all the the GC functions and various runtime calls, and opaque predefined closure objects. But if you really want to dig into the generated looking at the Cmm first is the way to go.

Urlencode/decode, different representation of the same string

I am a bit out of my comfort zone here, so I'm not even sure I'm aproaching the problem appropriately. Anyhow, here goes:
So I have a problem where I shall hash some info with sha1 that will work as that info's id.
when a client wants to signal what current info is being used, it sends a percent-encoded sha1-string.
So one example is, my server hashes some info and gets a hex representation like so:
44 c1 b1 0d 6a de ce 01 09 fd 27 bc 81 7f 0e 90 e3 b7 93 08
and the client sends me
D%c1%b1%0dj%de%ce%01%09%fd%27%bc%81%7f%0e%90%e3%b7%93%08
Removing the % we get
D c1 b1 0dj de ce 01 09 fd 27 bc 81 7f 0e 90 e3 b7 93 08
which matches my hash except for the beginning D and the j after the 0d, but replacing those with their ascii hex no, we have identical hash.
So, as I have read and understood the urlencoding, the standard would allow a client to send the D as either D or %44? So different clients would be able to send different representations off the same hash, and I will not be able to just compare them for equality?
I would prefer to be able to compare the urlencoded strings as they are when they are sent, but one way to do it would be to decode them, removing all '%' and get the ascii hex value for whatever mismatch I get, much like the D and the j in my above example.
This all seems to be a very annoying way to do things, am I missing something, please tell me I am? :)
I am doing this in node.js but I suppose the solution would be language/platform agnostic.
I made this crude solution for now:
var unreserved = 'A B C D E F G H I J S O N K L M N O P Q R S T U V W X Y Za b c d e f g h i j s o n k l m n o p q r s t u v w x y z + 1 2 3 4 5 6 7 8 9 0 - _ . ~';
function hexToPercent(hex){
var index = 0,
end = hex.length,
delimiter = '%',
step = 2,
result = '',
tmp = '';
if(end % step !== 0){
console.log('\'' + hex + '\' must be dividable by ' + step + '.');
return result;
}
while(index < end){
tmp = hex.slice(index, index + step);
if(unreserved.indexOf(String.fromCharCode('0x' + tmp)) !== -1){
result = result + String.fromCharCode('0x' + tmp);
}
else{
result = result + delimiter + tmp;
}
index = index + step;
}
return result;
}

How does ASN.1 encode an object identifier?

I am having trouble understanding the basic concepts of ASN.1.
If a type is an OID, does the corresponding number get actually encoded in the binary data?
For instance in this definition:
id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
Does the corresponding 1.3.6.1.5.5.7.48.1 get encoded in the binary exactly like this?
I am asking this because I am trying to understand a specific value I see in a DER file (a certificate), which is 04020500, and I am not sure how to interpret it.
Yes, the OID is encoded in the binary data. The OID 1.3.6.1.5.5.7.48.1 you mention becomes 2b 06 01 05 05 07 30 01 (the first two numbers are encoded in a single byte, all remaining numbers are encoded in a single bytes as well because they're all smaller than 128).
A nice description of OID encoding is found here.
But the best way to analyze your ASN.1 data is to paste in into an online decoder, e.g. http://lapo.it/asn1js/.
If all your digits are less than or equal to 127 then you are very lucky because they can be represented with a single octet each. The tricky part is when you have larger numbers which are common, such as 1.2.840.113549.1.1.5 (sha1WithRsaEncryption). These examples focus on decoding, but encoding is just the opposite.
1. First two 'digits' are represented with a single byte
You can decode by reading the first byte into an integer
var firstByteNumber = 42;
var firstDigit = firstByteNumber / 40;
var secondDigit = firstByteNumber % 40;
Produces the values
1.2
2. Subsequent bytes are represented using Variable Length Quantity, also called base 128.
VLQ has two forms,
Short Form - If the octet starts with 0, then it is simply represented using the remaining 7 bits.
Long Form - If the octet starts with a 1 (most significant bit), combine the next 7 bits of that octet plus the 7 bits of each subsequent octet until you come across an octet with a 0 as the most significant bit (this marks the last octet).
The value 840 would be represented with the following two bytes,
10000110
01001000
Combine to 00001101001000 and read as int.
Great resource for BER encoding, http://luca.ntop.org/Teaching/Appunti/asn1.html
The first octet has value 40 * value1 + value2. (This is unambiguous,
since value1 is limited to values 0, 1, and 2; value2 is limited to
the range 0 to 39 when value1 is 0 or 1; and, according to X.208, n is
always at least 2.)
The following octets, if any, encode value3, ...,
valuen. Each value is encoded base 128, most significant digit first,
with as few digits as possible, and the most significant bit of each
octet except the last in the value's encoding set to "1." Example: The
first octet of the BER encoding of RSA Data Security, Inc.'s object
identifier is 40 * 1 + 2 = 42 = 2a16. The encoding of 840 = 6 * 128 +
4816 is 86 48 and the encoding of 113549 = 6 * 1282 + 7716 * 128 + d16
is 86 f7 0d. This leads to the following BER encoding:
06 06 2a 86 48 86 f7 0d
Finally, here is a OID decoder I just wrote in Perl.
sub getOid {
my $bytes = shift;
#first 2 nodes are 'special';
use integer;
my $firstByte = shift #$bytes;
my $number = unpack "C", $firstByte;
my $nodeFirst = $number / 40;
my $nodeSecond = $number % 40;
my #oidDigits = ($nodeFirst, $nodeSecond);
while (#$bytes) {
my $num = convertFromVLQ($bytes);
push #oidDigits, $num;
}
return join '.', #oidDigits;
}
sub convertFromVLQ {
my $bytes = shift;
my $firstByte = shift #$bytes;
my $bitString = unpack "B*", $firstByte;
my $firstBit = substr $bitString, 0, 1;
my $remainingBits = substr $bitString, 1, 7;
my $remainingByte = pack "B*", '0' . $remainingBits;
my $remainingInt = unpack "C", $remainingByte;
if ($firstBit eq '0') {
return $remainingInt;
}
else {
my $bitBuilder = $remainingBits;
my $nextFirstBit = "1";
while ($nextFirstBit eq "1") {
my $nextByte = shift #$bytes;
my $nextBits = unpack "B*", $nextByte;
$nextFirstBit = substr $nextBits, 0, 1;
my $nextSevenBits = substr $nextBits, 1, 7;
$bitBuilder .= $nextSevenBits;
}
my $MAX_BITS = 32;
my $missingBits = $MAX_BITS - (length $bitBuilder);
my $padding = 0 x $missingBits;
$bitBuilder = $padding . $bitBuilder;
my $finalByte = pack "B*", $bitBuilder;
my $finalNumber = unpack "N", $finalByte;
return $finalNumber;
}
}
OID encoding for dummies :) :
each OID component is encoded to one or more bytes (octets)
OID encoding is just a concatenation of these OID component encodings
first two components are encoded in a special way (see below)
if OID component binary value has less than 7 bits, the encoding is just a single octet, holding the component value (note, most significant bit, leftmost, will always be 0)
otherwise, if it has 8 and more bits, the value is "spread" into multiple octets - split the binary representation into 7 bit chunks (from right), left-pad the first one with zeroes if needed, and form octets from these septets by adding most significant (left) bit 1, except from the last chunk, which will have bit 0 there.
first two components (X.Y) are encoded like it is a single component with a value 40*X + Y
This is a rewording of ITU-T recommendation X.690, chapter 8.19
This is a simplistic Python 3 implementation of the of above, resp. a string form of an object identifier into ASN.1 DER or BER form.
def encode_variable_length_quantity(v:int) -> list:
# Break it up in groups of 7 bits starting from the lowest significant bit
# For all the other groups of 7 bits than lowest one, set the MSB to 1
m = 0x00
output = []
while v >= 0x80:
output.insert(0, (v & 0x7f) | m)
v = v >> 7
m = 0x80
output.insert(0, v | m)
return output
def encode_oid_string(oid_str:str) -> tuple:
a = [int(x) for x in oid_str.split('.')]
oid = [a[0]*40 + a[1]] # First two items are coded by a1*40+a2
# A rest is Variable-length_quantity
for n in a[2:]:
oid.extend(encode_variable_length_quantity(n))
oid.insert(0, len(oid)) # Add a Length
oid.insert(0, 0x06) # Add a Type (0x06 for Object Identifier)
return tuple(oid)
if __name__ == '__main__':
oid = encode_oid_string("1.2.840.10045.3.1.7")
print(oid)

Resources