Absolute beginner at Assembly Code!


16 posts
by antiloquax » Sat May 19, 2012 6:58 pm
hellocode.png
hellocode.png (5.6 KiB) Viewed 3379 times

hellooutput.png
hellooutput.png (34.8 KiB) Viewed 3379 times


I have managed to get a simple "Hello World" program to work! :shock:
Hopefully, now I have more of an idea what the assembler program should look like, I will be able to do some more.
mark
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by tufty » Sat May 19, 2012 7:26 pm
Yay you!
Posts: 1376
Joined: Sun Sep 11, 2011 2:32 pm
by cheery » Sat May 19, 2012 7:32 pm
Very good! Oh and thank you. I'll probably find this very useful later on.

Here's something in return:
Code: Select all
grep __NR_ /usr/include/asm/unistd.h
User avatar
Posts: 219
Joined: Wed Jan 25, 2012 9:39 pm
by Dave_G_2 » Sat May 19, 2012 7:38 pm
@antiloquax

If you don't already have it, get yourself a list of the Linux System calls to use with swi.
User avatar
Posts: 196
Joined: Sat Apr 14, 2012 7:04 pm
by antiloquax » Sat May 19, 2012 10:55 pm
Thanks for your replies! I'm hoping to have a bit more time to play with assembly code tomorrow!
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by RaspberryPie » Tue May 22, 2012 6:48 pm
Keep posting working code, this is a very interesting topic..

cant wait for my pie!
A Raspberry a Day
Keep the Student at Play
So Get Your Slice of Pi
Let your programming Fly
User avatar
Posts: 20
Joined: Thu Apr 26, 2012 3:49 pm
Location: florida
by antiloquax » Mon May 28, 2012 1:41 pm
Okay, this is very basic, but I am learning from doing simple things:
Image

And this shows how I assembled and linked it and got the output.
Image

mark
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by antiloquax » Thu Jun 07, 2012 8:49 am
I've got a copy of Knuth's "The Art of Computer Programming". I see I am going to struggle with the level of the mathematics :oops:
Anyway, I was having a look at the first algorithm (Euclid's Greatest Common Divisor).
I came up with this. It's in asm, although I use "printf" to supply some output.
I'm sure this is not the best way to do it! But like I say, I am a beginner. It does seem to work.
Anyway, if you have any suggestions as to how I could improve on this effort, please let me know.
Image
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by tufty » Thu Jun 07, 2012 9:56 am
A few comments.

First, TAOCP is essential reading and you won't regret it.
Second, you can post your code direct using [ code ] markup.
Third, loopa and loopb are equivalent, and can be replaced by a single label
Fourth, line 30 seems to miss the case where you're <0

Simon
Posts: 1376
Joined: Sun Sep 11, 2011 2:32 pm
by antiloquax » Thu Jun 07, 2012 11:14 am
Hi Simon,
Thanks for your comments. I can't believe I didn't realise that I didn't need loopa and loopb (like I said, I'm a beginner).
In line 30, it's never going to be less than zero, since r4 is the remainder. I think I could have just put
Code: Select all
mov r3, r1

I've also been reading about using immediate values. It just so happens that the example from TAOCP works, but I think I should have used
Code: Select all
ldr r2, =6099
(for example).


Code: Select all
.section    .data

string:
    .asciz "Euclid's Algorithm: Greatest Common Divisor\n"
result:
    .asciz "Result: %d\n"

.text
    .globl  main

main:
    ldr r0, =string
    bl  printf

    ldr r2, =6099
    ldr r3, =2166

loopa:
loopb:
    sub r4, r2, r3
    cmp r4, r3
    movge   r2, r4
    bge     loopb

    cmp r4, $0
    movgt r2, r3
    movgt r3, r4
    bgt     loopa

    moveq   r1, r3
    ldr r0, =result
    bl printf
    mov r7, $1
    swi 0
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by tufty » Thu Jun 07, 2012 12:06 pm
antiloquax wrote:In line 30, it's never going to be less than zero, since r4 is the remainder.

insert facepalm.gif here.

Yep, a straight, non-conditional operand is more readable. there are reasons why you might want to use the conditional version, but I won't go into them here.
antiloquax wrote:I've also been reading about using immediate values. It just so happens that the example from TAOCP works, but I think I should have used
Code: Select all
ldr r2, =511
(for example).


It might work, but it's a horrible misuse, and it will bite you in the ass.

The LDRxx mnemonics /all/ load a register from memory or another register. You can't use them to load a literal value (except in the case of the ldr rn, =label construct, which is a shorthand provided by the assembler, not the instruction set itself).

To load a literal value, you need to use MOVxxx, for example
Code: Select all
mov r0, #0xf00d

Where this gets sticky is that the ARM instruction set is strictly 32 bits only, and with a certain number of those bits used for encoding the instruction itself, you aren't going to be able to encode all 32 bits of a literal value. In fact, you can only do 16 bits at a time (12 bits prior to ARMv6T2). This is a major bummer. There are two ways round this:
Code: Select all
.code32
myRoutine:
...
  ldr r0, _myLiteral  ; load my literal
...
  bx lr
.ltorg
_myLiteral:
  dc.l 0xfeedface

This is the approach most compilers take - literals are grouped into pools spaced between functions (most commonly directly after the function using them) and then referred to as above. The other approach, which is not compatible with older processors, is
Code: Select all
  mov  r0, #0xface
  movt r0, #0xfeed

It's slightly more succinct in terms of readability, and potentially marginally faster, but doesn't save any space (it's still 64 bits).

You can kinda do something like the latter on older processors, knowing that the immediate values you can load direct are 8 bits in length with a 4 bit rotation. As you can imagine, loading immediate values like this gets a "little" involved, and takes longer and more space than the literal pool approach.
Simon
Posts: 1376
Joined: Sun Sep 11, 2011 2:32 pm
by antiloquax » Thu Jun 07, 2012 2:24 pm
Thanks again!
I'm afraid you've lost me a bit with the material on loading literals.
I'll have to learn a lot more asm to understand what you are saying.
This is the first program I have ever written in asm (as opposed to copying from websites and making minor changes).
I do plan to adapt the code so it will take input from the user. That will make the problem about immediate values irrelevant, I think.
Mark
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by antiloquax » Thu Jun 07, 2012 6:37 pm
Donald Knuth wrote:Many computer users feel that input and output are not actually part of "real" programming; input and output are considered to be tedious tasks that people must perform only because they need to get information in and out of a machine.


Okay, I've had another look at this code and decided to use variables to avoid the mess I was getting into. This goes into my .data section.
Code: Select all
m:
    .long   6099
n:
    .long   2166


These are the values Knuth gives in exercise 4 (page 9). :geek:
Then I've loaded the numbers into my registers like this. I am assuming this is right - first load the address and then a 4-byte chunk into the register. It works, anyway, on my RPi.
Code: Select all
    ldr r5, =m
    ldr r2, [r5], $4

    ldr r5, =n
    ldr r3, [r5], $4


I have also been having a go with some inline use of ASM from C - code. I may post this later.
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by antiloquax » Fri Jun 08, 2012 5:40 pm
I am a bit stuck. I've been trying to work out how to print a single character to the screen using ASM (mainly because I am interested in converting numbers to strings and printing them without using "printf").

This page seems to be a good place to look at the syscalls.

My initial aim is to write a simple loop that will count down from 9 to 0 and use the counter to print the number. I've tried adding 48 to the counter (to get to the ascii values for numerals) but I haven't managed to get it to work. I've got the loop working okay and tried to load the correct value into r1, but no numbers came out. I'm not sure if it is something do do with putting a value into r2 (for a string, I've put the length in that register).
Is it to do with data-types? Do I have to tell the processor that I am using byte-values? I tried "ldrb r0" but that didn't work either.
Anyway, if someone knows how to do this, I'd be interested.
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by cheery » Fri Jun 08, 2012 6:36 pm
You're looking for __NR_WRITE (4). That's sys_write. "man 2 write" tells you what it needs. (ssize_t write(int fd, const void *buf, size_t count)). You want to write to STDOUT, which has fixed file descriptor number 1.

Code: Select all
digit = pow(10, index)
[--buf] = '0' + (value / digit % 10)
User avatar
Posts: 219
Joined: Wed Jan 25, 2012 9:39 pm
by antiloquax » Fri Jun 08, 2012 6:53 pm
Thanks Cheery. I'll try that.
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am