asm printf?


41 posts   Page 1 of 2   1, 2
by dpawson » Fri Jun 01, 2012 9:54 am
I can now call asm from a C shell.
Rather than do this, are there any documented... system calls? I.e. can I get I/O via some form of
call to write to the console/read from it?
Any pointers to hardware access too from asm The IO strip or the leds?
Has anyone documented this please?
Any pointers please?



TIA Dave
Posts: 115
Joined: Mon Nov 14, 2011 5:05 pm
by AndrewS » Fri Jun 01, 2012 10:19 am
There was a "linux assembly programming" series of tutorials in LinuxFormat recently. IIRC the file you might be looking for is http://lxr.free-electrons.com/source/in ... =3.1;a=arm
or http://lxr.free-electrons.com/source/ar ... =3.1;a=arm

And google seems to pick out a few linux assembly tutorials too ;)

Regarding "the IO strip" see http://elinux.org/Rpi_Low-level_peripherals and http://www.raspberrypi.org/wp-content/u ... herals.pdf

Best of luck :)
User avatar
Posts: 3626
Joined: Sun Apr 22, 2012 4:50 pm
Location: Cambridge, UK
by dpawson » Fri Jun 01, 2012 10:49 am
Are they generic, or specific to Debian... or rpi?
http://lxr.free-electrons.com/source/ar ... =3.1;a=arm
2005 seems rather old for rpi?

Thanks for the GPIO references. Looks like that is complete. I'll chase it up
for sw i/f.

Dave
Posts: 115
Joined: Mon Nov 14, 2011 5:05 pm
by rurwin » Fri Jun 01, 2012 11:11 am
A library is a library; you can call all the C library from assembler just like you can from C. You need to kow the C calling convention, which says what to put on the stack and what to put in registers and what to do after the call to get the result and tidy up, but all that is simple enough.

So the printf for assembler... is printf.

And it was a pain to find, but the EABI calling conventions for Debian Armel is documented here.
User avatar
Forum Moderator
Forum Moderator
Posts: 2933
Joined: Mon Jan 09, 2012 3:16 pm
by dpawson » Fri Jun 01, 2012 11:19 am
http://omappedia.org/wiki/Writing_ARM_Assembly

Thanks for that.

Clarifies the interface, c-asm.
Should I take it then that there is no svc call for console I/O?
I want to remain in asm and drop the C shell.

Dave
Posts: 115
Joined: Mon Nov 14, 2011 5:05 pm
by funnel » Fri Jun 01, 2012 11:28 am
In this free book "Programming From The Ground Up" you can find sample codes for x86 linux asm.

In short, everything you write to /dev/stdout will appear on the screen. From asm you open it as a file and write to it.
Posts: 46
Joined: Sat May 05, 2012 8:00 am
by AndrewS » Fri Jun 01, 2012 11:47 am
dpawson wrote:Are they generic, or specific to Debian... or rpi?

The link I provided is only "specific" to the 3.1.x release of the Linux kernel.

http://lxr.free-electrons.com/source/arch/arm/include/asm/unistd.h?v=3.1;a=arm
2005 seems rather old for rpi?

That's because it's such a low-level stable interface, it doesn't change much (which is a good thing). Everything else layers up on top of this... :geek:
User avatar
Posts: 3626
Joined: Sun Apr 22, 2012 4:50 pm
Location: Cambridge, UK
by AndrewS » Fri Jun 01, 2012 11:56 am
Found the LXF Coding Academy Assembly tutorials - http://www.linuxformat.com/archives?issue=154 to issue 157 - but only available to subscribers.
User avatar
Posts: 3626
Joined: Sun Apr 22, 2012 4:50 pm
Location: Cambridge, UK
by rurwin » Fri Jun 01, 2012 12:39 pm
dpawson wrote:Should I take it then that there is no svc call for console I/O?
I want to remain in asm and drop the C shell.

Then you need to know what crt0 does so you can replace it with your code. This thread should give you a few hints as to where to look.

The calls to the kernel as opposed to the calls to the C library are those functions documented in section 2 of man as opposed to section 3. However I do not know if this makes a difference to code you write. It might be possible to use a software interupt or whatever ARM has, but you'd need to dive further into Armel and Linux source to find out. Maybe if you find the source to the C libraries that wrap those functions...

You are now going where very few people bother going. For most programmers, C with a few functions in assembler is all they ever need. So the source code for crt0 and those libraries is likely to be more useful than any other resource. In particular I can point the way, but I've not been there for decades and never in Linux or ARM.
User avatar
Forum Moderator
Forum Moderator
Posts: 2933
Joined: Mon Jan 09, 2012 3:16 pm
by AndrewS » Fri Jun 01, 2012 1:33 pm
I'd agree with rurwin - "pure assembly" is really only useful if you're building truly tiny systems - look at http://asm.sourceforge.net/asmutils.html and http://www.fefe.de/dietlibc/ for examples (and possibly more useful links). But with the abundant resources of the RPi, it doesn't really seem necessary - just stick with C. Unless you're doing it purely as a learning exercise of course :)
User avatar
Posts: 3626
Joined: Sun Apr 22, 2012 4:50 pm
Location: Cambridge, UK
by antiloquax » Fri Jun 01, 2012 2:51 pm
Image

Sorry - I know I've posted this somewhere else, but it is relevant here, I think.

I don't fully understand this, but it looks like the string is loaded into r1, the string's length goes in r2. Then we make r7 hold the value 4. This must the code to print to the screen, I think.
(To end a program, you make this register hold 1, as you can see later ... ).
Then "swi $0" is the message to the kernel to do something.
I'm keen to learn some more assembly code (just out of interest rather than for any practical project).
:D :D
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by AndrewS » Fri Jun 01, 2012 3:47 pm
Yeah, this ties up with the link I posted earlier http://lxr.free-electrons.com/source/ar ... =3.1;a=arm

4 is __NR_write and 1 is __NR_exit
But that's about as far as my knowledge goes, you're really best off buying/borrowing a book or something :)
User avatar
Posts: 3626
Joined: Sun Apr 22, 2012 4:50 pm
Location: Cambridge, UK
by rurwin » Fri Jun 01, 2012 5:15 pm
antiloquax wrote:Image

Sorry - I know I've posted this somewhere else, but it is relevant here, I think.

I don't fully understand this, but it looks like the string is loaded into r1, the string's length goes in r2. Then we make r7 hold the value 4. This must the code to print to the screen, I think.
(To end a program, you make this register hold 1, as you can see later ... ).
Then "swi $0" is the message to the kernel to do something.


AndrewS wrote:Yeah, this ties up with the link I posted earlier http://lxr.free-electrons.com/source/ar ... =3.1;a=arm

4 is __NR_write and 1 is __NR_exit


OK, that makes sense. The C declaration of write(2) is:
Code: Select all
ssize_t write(int fd, const void *buf, size_t count);


So r0 is the file descriptor. fd 1 is stdout.
r1 is a pointer to the string
r2 is the size of the string
r7 is the system call to use.
User avatar
Forum Moderator
Forum Moderator
Posts: 2933
Joined: Mon Jan 09, 2012 3:16 pm
by tufty » Fri Jun 01, 2012 7:32 pm
10 internet points for rurwin :)

syscalls are done by shoving the parameters into the first 6 registers (it gets a tad more tricky if you have more than 6 arguments), the syscall number into r7, and executing 'swi 0'. This triggers a "software interrupt" (hence 'swi', although the opcode has now been renamed to 'svc' or "supervisor call") which causes execution to jump to the SVC vector in the ARM vector table (and, in the process, puts the processor into a privileged execution state), which dispatches your call off to the relevant handler. about the only tricky thing is if you have 64-bit arguments, as they have to be aligned starting in even-numbered registers. Not sure if any of the Linux syscalls need that, though.

Chapter and verse on argument passing can be had from the Procedure Call Standard for the ARM Architecture

Simon
Posts: 1368
Joined: Sun Sep 11, 2011 2:32 pm
by dpawson » Mon Jun 04, 2012 9:42 am
AndrewS wrote:I'd agree with rurwin - "pure assembly" is really only useful if you're building truly tiny systems - look at http://asm.sourceforge.net/asmutils.html and http://www.fefe.de/dietlibc/ for examples (and possibly more useful links). But with the abundant resources of the RPi, it doesn't really seem necessary - just stick with C. Unless you're doing it purely as a learning exercise of course


Exactly why I'm doing it, purely as a learning exercise.... then documenting it for others.
Agreed it isn't necessary, but then again, how many are doing anything 'necessary' with rpi?

Tks for the pointers all.
Posts: 115
Joined: Mon Nov 14, 2011 5:05 pm
by dpawson » Mon Jun 04, 2012 11:23 am
antiloquax wrote:Image



I don't fully understand this, but it looks like the string is loaded into r1, the string's length goes in r2. Then we make r7 hold the value 4. This must the code to print to the screen, I think.
(To end a program, you make this register hold 1, as you can see later ... ).
Then "swi $0" is the message to the kernel to do something.
I'm keen to learn some more assembly code (just out of interest rather than for any practical project).
:D :D


As per the image
(I can't get the midori browser to work with the forum or I'd paste it)

.data
msg:
.ascii "Hello World\n"
len = . - msg

.text

.globl _wrmsg
_wrmsg:
mov r0, $1
ldr r1, =msg
ldr r2, =len
mov r7, $4
svc $0

mov r0, $0
mov r7, $1
svc $0

# bx lr appending this fails to return to the calling C code

I think that is the code given in the image.
OK, it works. Produces output.

Why two SVC calls please?
One to svc ??? 4
then one to svc ??? 1

I can call this from C...
With bx lr appended to the end of the asm fails to return though?

Thanks. DaveP
Posts: 115
Joined: Mon Nov 14, 2011 5:05 pm
by dpawson » Mon Jun 04, 2012 11:32 am
Duh.

RTFM

The comments above imply the second svc is to end the program.
I.e. can delete all after the call to svc #0

(I have changed all the literals from $x to #x in line with ARM conventions)



I guess if I could sort out a register setup this would allow
a start without a call from C. later.
ld parameters?

Now works and returns from asm to the C code.

Thanks to all for the help.

Dave
Posts: 115
Joined: Mon Nov 14, 2011 5:05 pm
by rurwin » Mon Jun 04, 2012 11:39 am
It seems to me that the code in the image is to be executed on its own without a C wrapper, because it starts with a _start label. IIRC, crt0 starts with _start and then calls _main. So I'd guess the code in the image is a direct example of what you need to do.
User avatar
Forum Moderator
Forum Moderator
Posts: 2933
Joined: Mon Jan 09, 2012 3:16 pm
by dpawson » Mon Jun 04, 2012 12:10 pm
rurwin wrote:It seems to me that the code in the image is to be executed on its own without a C wrapper, because it starts with a _start label. IIRC, crt0 starts with _start and then calls _main. So I'd guess the code in the image is a direct example of what you need to do.



Yep... or nearly.
Quite standalone
(Has anyone got a browser working with this forum under Debian /rpi?)

.data
msg:
.ascii "Hello World\n"
len = . - msg
.align 8

.text @ wozzat for?
.global main
main: @keep gcc happy
mov r0, #1
ldr r1, =msg
ldr r2, =len
mov r7, #4
svc #0 @service call to 4, print

mov r0, #0
mov r7, #1
svc #0 @service call to 'return' to the OS
.end


That works. HTH Others.

Who needs cissy C @-)
Posts: 115
Joined: Mon Nov 14, 2011 5:05 pm
by antiloquax » Mon Jun 04, 2012 9:23 pm
Hi,
Sorry, I missed some of the replies on here - forgot to "watch".

I have been trying to work out how to print a number to the screen. So far, no luck. I've been reading some of the material on syscalls, but I can't get it to work :(
In the mean-time, I've been playing around with more extremely simple code. Here's a little program that doubles the number 7!
Image
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by rurwin » Mon Jun 04, 2012 10:53 pm
antiloquax wrote:I have been trying to work out how to print a number to the screen. So far, no luck. I've been reading some of the material on syscalls, but I can't get it to work :(

That's the problem with assembler; you need to do all the work yourself, unless you link in the C libraries and call them.

The way we used to do it on the PDP-11 was to have a table of powers of ten. Start at the high end and start subtracting the highest power of ten from your number until it goes negative then take the number of times you subtracted (minus one) plus the value of ASCII '0' (48) and print that as a character. Then do the same for the next power of ten and so on down. Handling leading zero suppression and negative numbers is left as an exercise for the interested reader. ;-)
User avatar
Forum Moderator
Forum Moderator
Posts: 2933
Joined: Mon Jan 09, 2012 3:16 pm
by AndrewS » Mon Jun 04, 2012 11:54 pm
antiloquax wrote:I have been trying to work out how to print a number to the screen. So far, no luck. I've been reading some of the material on syscalls, but I can't get it to work :(

The tutorial code for the LXF articles I linked to earlier is publicly available. The source-code download from LXF156 ( http://www.linuxformat.com/includes/dow ... 6.code.tgz ) contains a library.asm file which contains (amongst others) a lib_print_number function. It's written in x86, so it'll need some conversion to ARM, but the techniques might give you a head start? 8-)
User avatar
Posts: 3626
Joined: Sun Apr 22, 2012 4:50 pm
Location: Cambridge, UK
by antiloquax » Tue Jun 05, 2012 10:45 am
Thanks Andrew and rurwin. I've downloaded the library.asm file.
In the mean time, I've been playing with a simple loop program (which uses the C "printf" function: cheating ;) )
Code: Select all
.section    .data
string:
    .asciz "Looping: %d\n"
.text
    .globl  main

main:
    mov r5, $10
.loop:
    mov r1, r5
    ldr r0, =string
    bl  printf
    subs    r5, r5, $1   
    bne .loop
    mov r7, $1
    swi $0


I found that I had to use a different register from r1 for my counter. I'm not really sure why, but it didn't work when I tried using r1. Anyway, that is why I am using r5 to count down and then moving the count into r1 before printing.
Someone will probably explain it better, but I use "subs" to decrement my counter and set the condition code. That way, I don't need to do "cmp", because "bne" will branch if our counter is not zero. I tried using "bpl" (branch if positive or zero), and that worked nicely too.
mark

By the way, rurwin, where did you use a PDP-11? I'm reading Stephen Levy's "Hackers" at the moment and was very interested by the material about the PDP-1 at MIT.
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by dpawson » Tue Jun 05, 2012 1:57 pm
antiloquax wrote:Hi,
Sorry, I missed some of the replies on here - forgot to "watch".

I have been trying to work out how to print a number to the screen. So far, no luck. I've been reading some of the material on syscalls, but I can't get it to work :(
In the mean-time, I've been playing around with more extremely simple code. Here's a little program that doubles the number 7!


http://www.tofla.iconbar.com/tofla/arm/arm02/index.htm
Looks good, as an exercise too.

Gives integer division.

HTH
Posts: 115
Joined: Mon Nov 14, 2011 5:05 pm
by antiloquax » Tue Jun 05, 2012 2:03 pm
That looks interesting. I'll have a read.
I started to think about converting integers into ascii strings and then remembered that the RPi's arm doesn't have built in division!
I used a similar idea to the one rurwin mentioned in a little Python program I wrote to do UK National Curriculum grid multiplication. I wanted to get the values of the hundreds, tens and units etc "columns". Here's the function I wrote ("split").

Image
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am