PDA

View Full Version : ASM on Mac OS X




Cromulent
Mar 17, 2008, 05:45 PM
I'm having a real problem getting to stage one of ASM on Mac OS X. Tutorials and online books either assume you are using MASM or use Linux specific calls. I do not know enough (well any at all really) to be able to see what I am doing wrong. I managed to get one piece of code to assemble and link correctly but the code does nothing (I think it is because it uses int 0x080 which is a Linux kernel call), how did you guys go about learning ASM?

I'd preferably like to just read through a book and use the code as is just to give myself a grounding but that seems unlikely now that I look closer at ASM and the fragmentation of the language into different assemblers and operating systems. I guess that is the price to be paid for low level programming though.



Cromulent
Mar 17, 2008, 06:32 PM
Okay after a bit of hunting I've found a good reference guide. For some reason I didn't think ADC had any assembly related documentation. Apparently it does, I guess it just means that I will need to convert every example into Mac OS X friendly syntax. Should help with learning anyway.

http://developer.apple.com/documentation/DeveloperTools/Reference/Assembler/ASMIntroduction/chapter_1_section_1.html#//apple_ref/doc/uid/TP30000851-CH211-DontLinkElementID_14

Amdahl
Mar 17, 2008, 06:51 PM
Although there is nothing wrong with learning assembler on OS X, it is even more of a challenge. Linux or DOS/Windows would be the best platform to learn x86 assembler with a book. After that, you just learn the OS specific differences.

One helper on OS X is to use the Show Assembly menu in Xcode that lets you see how a piece of C code looks after translation to assembly.

Muncher
Mar 17, 2008, 07:37 PM
Although there is nothing wrong with learning assembler on OS X, it is even more of a challenge. Linux or DOS/Windows would be the best platform to learn x86 assembler with a book. After that, you just learn the OS specific differences.

One helper on OS X is to use the Show Assembly menu in Xcode that lets you see how a piece of C code looks after translation to assembly.

Very true. I would actually recommend windows starting out, because there is so much material for that OS on asm. Alternately, and interesting solution would be to get an old computer with a floppy or emulate it in Q, and load MenuetOS on to it. MenuetOS is a graphical operating system that runs on assembly. I read about it a while ago, and it looked pretty cool.

gnasher729
Mar 17, 2008, 08:03 PM
I would first read up on the x86 and PowerPC instruction sets (check out http://www.intel.com/products/processor/manuals/ for the x86 manuals). No point in trying to write assembler code if you don't know the processor instruction set.

Next thing I would write some very, very simple C functions in XCode, switch the compiler to IA32 only, and then "Show Assembly Code" in the "Build" menu. That will show you an assembler file equivalent to the source code, so you can learn the syntax and programming from there.

Next thing you can include .s files in your projects, with your own code. Or you use the gcc extensions to add asm code directly to a C or C++ or Objective-C function, but that is a major pain.

sord
Mar 17, 2008, 09:47 PM
Next thing I would write some very, very simple C functions in XCode, switch the compiler to IA32 only, and then "Show Assembly Code" in the "Build" menu. That will show you an assembler file equivalent to the source code, so you can learn the syntax and programming from there.
Also, take what the compiler gives you "with a grain of salt". Generated assembler is usually horrible compared to hand written.

For example here is GCCs version of PPC strlen:
stmw r30,0xfff8(r1)
stwu r1,0xffc0(r1)
or r30,r1,r1
stw r3,0x58(r30)
lwz r0,0x58(r30)
stw r0,0x18(r30)
b 0x2ac4
0x2ab8:
lwz r2,0x18(r30)
addi r0,r2,0x1
stw r0,0x18(r30)
0x2ac4:
lwz r2,0x18(r30)
lbz r0,0x0(r2)
extsb r0,r0
cmpwi cr7,r0,0x0
bne cr7,0x2ab8
lwz r2,0x18(r30)
lwz r0,0x58(r30)
subf r0,r0,r2
or r3,r0,r0
lwz r1,0x0(r1)
lmw r30,0xfff8(r1)
blr

Which can easily be reduced to:
or r2, r3, r3
b compare
loop:
addi r2, r2, 0x1
compare:
lbz r0, 0x0(r2)
cmpwi cr7, r0, 0x0
bne cr7, loop
subf r3, r3, r2
blr

Update: Mini-rant - this is why Intel, IBM, (and previously Metrowerks) were able to sell their products - GCC produces bad code. Here is an example of the same code (from same C file) by Metrowerks:
mr r2, r3
b *+8
addi r2, r2, 1
lbz r0, 0(r2)
extsb. r0, r0
bne *-12
subf r3, r3, r2
blr

Cromulent
Mar 18, 2008, 03:53 PM
One helper on OS X is to use the Show Assembly menu in Xcode that lets you see how a piece of C code looks after translation to assembly.

The problem with that is that even with a very simple program (Hello World) it spits out tons of rubbish. Most of which I imagine is completely irrelevant to the program (I assume most of it is setting up etc).

For instance Hello World spits out the following for me:

.section __DWARF,__debug_frame,regular,debug
Lsection__debug_frame:
.section __DWARF,__debug_info,regular,debug
Lsection__debug_info:
.section __DWARF,__debug_abbrev,regular,debug
Lsection__debug_abbrev:
.section __DWARF,__debug_aranges,regular,debug
Lsection__debug_aranges:
.section __DWARF,__debug_macinfo,regular,debug
Lsection__debug_macinfo:
.section __DWARF,__debug_line,regular,debug
Lsection__debug_line:
.section __DWARF,__debug_loc,regular,debug
Lsection__debug_loc:
.section __DWARF,__debug_pubnames,regular,debug
Lsection__debug_pubnames:
.section __DWARF,__debug_pubtypes,regular,debug
Lsection__debug_pubtypes:
.section __DWARF,__debug_str,regular,debug
Lsection__debug_str:
.section __DWARF,__debug_ranges,regular,debug
Lsection__debug_ranges:
.section __DWARF,__debug_abbrev,regular,debug
Ldebug_abbrev0:
.section __DWARF,__debug_info,regular,debug
Ldebug_info0:
.section __DWARF,__debug_line,regular,debug
Ldebug_line0:
.text
Ltext0:
.cstring
LC0:
.ascii "Hello, World!\0"
.text
.globl _main
.private_extern _main
_main:
LFB3:
LM1:
LVL0:
pushl %ebp
LCFI0:
movl %esp, %ebp
LCFI1:
subl $24, %esp
LCFI2:
LM2:
movl $LC0, (%esp)
call L_puts$stub
LM3:
xorl %eax, %eax
leave
ret
LFE3:
.section __DWARF,__debug_frame,regular,debug
Lframe0:
.set L$set$0,LECIE0-LSCIE0
.long L$set$0
LSCIE0:
.long 0xffffffff
.byte 0x1
.ascii "\0"
.byte 0x1
.byte 0x7c
.byte 0x8
.byte 0xc
.byte 0x4
.byte 0x4
.byte 0x88
.byte 0x1
.align 2
LECIE0:
LSFDE0:
.set L$set$1,LEFDE0-LASFDE0
.long L$set$1
LASFDE0:
.set L$set$2,Lframe0-Lsection__debug_frame
.long L$set$2
.long LFB3
.set L$set$3,LFE3-LFB3
.long L$set$3
.byte 0x4
.set L$set$4,LCFI0-LFB3
.long L$set$4
.byte 0xe
.byte 0x8
.byte 0x85
.byte 0x2
.byte 0x4
.set L$set$5,LCFI1-LCFI0
.long L$set$5
.byte 0xd
.byte 0x5
.align 2
LEFDE0:
.text
Letext0:
.section __DWARF,__debug_info,regular,debug
.long 0x1b9
.word 0x2
.set L$set$6,Ldebug_abbrev0-Lsection__debug_abbrev
.long L$set$6
.byte 0x4
.byte 0x1
.ascii "GNU C 4.0.1 (Apple Inc. build 5470) (Aspen 5470.3)\0"
.byte 0x1
.ascii "/Users/simon/Documents/Development/Assembly/Hello World/main.c\0"
.long Ltext0
.long Letext0
.set L$set$7,Ldebug_line0-Lsection__debug_line
.long L$set$7
.byte 0x2
.byte 0x1
.byte 0x6
.ascii "signed char\0"
.byte 0x2
.byte 0x1
.byte 0x8
.ascii "unsigned char\0"
.byte 0x2
.byte 0x2
.byte 0x5
.ascii "short int\0"
.byte 0x2
.byte 0x2
.byte 0x7
.ascii "short unsigned int\0"
.byte 0x2
.byte 0x4
.byte 0x5
.ascii "int\0"
.byte 0x2
.byte 0x4
.byte 0x7
.ascii "unsigned int\0"
.byte 0x2
.byte 0x8
.byte 0x5
.ascii "long long int\0"
.byte 0x2
.byte 0x8
.byte 0x7
.ascii "long long unsigned int\0"
.byte 0x2
.byte 0x4
.byte 0x5
.ascii "long int\0"
.byte 0x3
.byte 0x4
.byte 0x7
.byte 0x2
.byte 0x1
.byte 0x6
.ascii "char\0"
.byte 0x2
.byte 0x4
.byte 0x7
.ascii "long unsigned int\0"
.byte 0x4
.byte 0x4
.long 0x142
.byte 0x5
.long 0x11f
.byte 0x6
.byte 0x1
.ascii "main\0"
.byte 0x1
.byte 0x3
.byte 0x1
.long 0xce
.long LFB3
.long LFE3
.byte 0x1
.byte 0x55
.long 0x182
.byte 0x7
.ascii "argc\0"
.byte 0x1
.byte 0x3
.long 0xce
.byte 0x2
.byte 0x75
.byte 0x8
.byte 0x7
.ascii "argv\0"
.byte 0x1
.byte 0x3
.long 0x182
.byte 0x2
.byte 0x75
.byte 0xc
.byte 0x0
.byte 0x4
.byte 0x4
.long 0x13c
.byte 0x8
.long 0xce
.long 0x193
.byte 0x9
.byte 0x0
.byte 0xa
.ascii "__CFConstantStringClassReference\0"
.long 0x188
.byte 0x1
.byte 0x1
.byte 0x1
.byte 0x0
.section __DWARF,__debug_abbrev,regular,debug
.byte 0x1
.byte 0x11
.byte 0x1
.byte 0x25
.byte 0x8
.byte 0x13
.byte 0xb
.byte 0x3
.byte 0x8
.byte 0x11
.byte 0x1
.byte 0x12
.byte 0x1
.byte 0x10
.byte 0x6
.byte 0x0
.byte 0x0
.byte 0x2
.byte 0x24
.byte 0x0
.byte 0xb
.byte 0xb
.byte 0x3e
.byte 0xb
.byte 0x3
.byte 0x8
.byte 0x0
.byte 0x0
.byte 0x3
.byte 0x24
.byte 0x0
.byte 0xb
.byte 0xb
.byte 0x3e
.byte 0xb
.byte 0x0
.byte 0x0
.byte 0x4
.byte 0xf
.byte 0x0
.byte 0xb
.byte 0xb
.byte 0x49
.byte 0x13
.byte 0x0
.byte 0x0
.byte 0x5
.byte 0x26
.byte 0x0
.byte 0x49
.byte 0x13
.byte 0x0
.byte 0x0
.byte 0x6
.byte 0x2e
.byte 0x1
.byte 0x3f
.byte 0xc
.byte 0x3
.byte 0x8
.byte 0x3a
.byte 0xb
.byte 0x3b
.byte 0xb
.byte 0x27
.byte 0xc
.byte 0x49
.byte 0x13
.byte 0x11
.byte 0x1
.byte 0x12
.byte 0x1
.byte 0x40
.byte 0xa
.byte 0x1
.byte 0x13
.byte 0x0
.byte 0x0
.byte 0x7
.byte 0x5
.byte 0x0
.byte 0x3
.byte 0x8
.byte 0x3a
.byte 0xb
.byte 0x3b
.byte 0xb
.byte 0x49
.byte 0x13
.byte 0x2
.byte 0xa
.byte 0x0
.byte 0x0
.byte 0x8
.byte 0x1
.byte 0x1
.byte 0x49
.byte 0x13
.byte 0x1
.byte 0x13
.byte 0x0
.byte 0x0
.byte 0x9
.byte 0x21
.byte 0x0
.byte 0x0
.byte 0x0
.byte 0xa
.byte 0x34
.byte 0x0
.byte 0x3
.byte 0x8
.byte 0x49
.byte 0x13
.byte 0x3f
.byte 0xc
.byte 0x34
.byte 0xc
.byte 0x3c
.byte 0xc
.byte 0x0
.byte 0x0
.byte 0x0
.section __DWARF,__debug_pubnames,regular,debug
.long 0x17
.word 0x2
.set L$set$8,Ldebug_info0-Lsection__debug_info
.long L$set$8
.long 0x1bd
.long 0x147
.ascii "main\0"
.long 0x0
.section __DWARF,__debug_pubtypes,regular,debug
.long 0xe
.word 0x2
.set L$set$9,Ldebug_info0-Lsection__debug_info
.long L$set$9
.long 0x1bd
.long 0x0
.section __DWARF,__debug_aranges,regular,debug
.long 0x1c
.word 0x2
.set L$set$10,Ldebug_info0-Lsection__debug_info
.long L$set$10
.byte 0x4
.byte 0x0
.word 0x0
.word 0x0
.long Ltext0
.set L$set$11,Letext0-Ltext0
.long L$set$11
.long 0x0
.long 0x0
.section __DWARF,__debug_line,regular,debug
.set L$set$12,LELT0-LSLT0
.long L$set$12
LSLT0:
.word 0x2
.set L$set$13,LELTP0-LASLTP0
.long L$set$13
LASLTP0:
.byte 0x1
.byte 0x1
.byte 0xf6
.byte 0xf5
.byte 0xa
.byte 0x0
.byte 0x1
.byte 0x1
.byte 0x1
.byte 0x1
.byte 0x0
.byte 0x0
.byte 0x0
.byte 0x1
.ascii "/Users/simon/Documents/Development/Assembly/Hello World"
.byte 0
.byte 0x0
.ascii "main.c\0"
.byte 0x1
.byte 0x0
.byte 0x0
.byte 0x0
LELTP0:
.byte 0x0
.byte 0x5
.byte 0x2
.long LM1
.byte 0x16
.byte 0x0
.byte 0x5
.byte 0x2
.long LM2
.byte 0x15
.byte 0x0
.byte 0x5
.byte 0x2
.long LM3
.byte 0x16
.byte 0x0
.byte 0x5
.byte 0x2
.long Letext0
.byte 0x0
.byte 0x1
.byte 0x1
LELT0:
.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5
L_puts$stub:
.indirect_symbol _puts
hlt ; hlt ; hlt ; hlt ; hlt
.subsections_via_symbols
I assume that this is the main part of the program and the rest is just C bloat?

.globl _main
.private_extern _main
_main:
LFB3:
LM1:
LVL0:
pushl %ebp
LCFI0:
movl %esp, %ebp
LCFI1:
subl $24, %esp
LCFI2:
LM2:
movl $LC0, (%esp)
call L_puts$stub
LM3:
xorl %eax, %eax
leave
ret

If I had a simple template to work with on an Intel Mac running Mac OS X Leopard it would help immensely. If anyone could just type the equivalent of an empty main() function in assembly I would be extremely grateful.

sord
Mar 18, 2008, 05:41 PM
You need the data section too (the part above the blob of code you gave that has .ascii "Hello, World!\0" in it)

Cromulent
Mar 18, 2008, 06:00 PM
You need the data section too (the part above the blob of code you gave that has .ascii "Hello, World!\0" in it)

The bit with the LC0 label?

I've been looking through the Intel developer manuals and they seem pretty comprehensive. I guess them combined with the NASM users guide, the Mac OS X assembly reference and a general X86 assembly book I should be able to work it out I guess.

I'll probably have more questions later though :).

Thanks for the help.

sord
Mar 18, 2008, 06:31 PM
Yes, the part with LC0 (which is referenced in the code blob by "movl $LC0, (%esp)").

Keep in mind that GCC/GAS will produce AT&T style assembler, however NASM, MASM, TASM, etc use Intel style assembler.

Cromulent
Mar 19, 2008, 04:46 PM
Yes, the part with LC0 (which is referenced in the code blob by "movl $LC0, (%esp)").

Keep in mind that GCC/GAS will produce AT&T style assembler, however NASM, MASM, TASM, etc use Intel style assembler.

Right. Thanks for that, I think I have enough information now to get on with it over the Easter weekend.

domain
Mar 19, 2008, 11:16 PM
Just out of curiosity (as someone that has used x86 assembly on/off for over a decade) what do you hope to accomplish with assembly on Mac OSX?

As with the others here, if you are attempting to learn x86 assembly, you will certainly have a far easier time using the extremely mature (and far better documented) assemblers found more prevalently on the Microsoft platforms (MASM in particular, but FASM or NASM might be good alternatives), and the general wealth of knowledge/examples for writing usable code that is available. On the other hand, you need to ensure you maintain a clear understanding of what is/is not available depending on what platform you are currently using...

I would also highly suggest staying as far away from compiler generated assembly as humanly possible (especially if you are letting the compiler do any level of optimization). What you will end up with the majority of the time will look very non-sensical, will likely be attempting to take advantages of non-standard features (or even bugs in certain processor families), and that does not follow a normal "logical" flow.

In the end however, assembly has really fallen out of favor so to speak, and outside of completely "stand-alone" code, or for optimizing specific sections of code that require absolute maximum speed (assuming you have the knowledge to even optimize it further then the compiler), it really doesn't provide much "benefit" persay.

lee1210
Mar 20, 2008, 08:19 AM
The problem with that is that even with a very simple program (Hello World) it spits out tons of rubbish. Most of which I imagine is completely irrelevant to the program (I assume most of it is setting up etc).

For instance Hello World spits out the following for me:
<snip>
If I had a simple template to work with on an Intel Mac running Mac OS X Leopard it would help immensely. If anyone could just type the equivalent of an empty main() function in assembly I would be extremely grateful.

The vast majority of what Xcode spit out is debug information. The default build includes all of that, so when you click a breakpoint in the IDE, etc. all of the debug info is there to achieve that for you.

I would take a different tact if you want to get compiler-generated ASM.

Take your hello world source:
#include <stdio.h>

int main(int argc, char *argv[]) {
printf("Hello World!\n");
return 0;
}

Then run this from the command line:
gcc -S helloworld.c

A file helloworld.s will be generated, mine looked like this:
.cstring
LC0:
.ascii "Hello World!\0"
.text
.globl _main
_main:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $20, %esp
call ___i686.get_pc_thunk.bx
"L00000000001$pb":
leal LC0-"L00000000001$pb"(%ebx), %eax
movl %eax, (%esp)
call L_puts$stub
movl $0, %eax
addl $20, %esp
popl %ebx
popl %ebp
ret
.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5
L_puts$stub:
.indirect_symbol _puts
hlt ; hlt ; hlt ; hlt ; hlt
.subsections_via_symbols
.section __TEXT,__textcoal_nt,coalesced,pure_instructions
.weak_definition ___i686.get_pc_thunk.bx
.private_extern ___i686.get_pc_thunk.bx
___i686.get_pc_thunk.bx:
movl (%esp), %ebx
ret


Perhaps not the MOST concise possible, but looks a lot nicer than the debug ridden output Xcode gave you (you may be able to turn this off and get nicer looking ASM, but I am not too familiar with all of the Xcode options).

For comparison, here's gcc's output, adding -g to the above to add debug symbols:
.stabs "/Users/lee/",100,0,2,Ltext0
.stabs "helloworld.c",100,0,2,Ltext0
.text
Ltext0:
.stabs "",102,0,0,0
.stabs "gcc2_compiled.",60,0,0,0
.stabs ":t(0,1)=(0,1)",128,0,0,0
.cstring
LC0:
.ascii "Hello World!\0"
.text
.globl _main
_main:
.stabd 46,0,0
.stabd 68,0,3
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $20, %esp
call ___i686.get_pc_thunk.bx
"L00000000001$pb":
.stabd 68,0,4
leal LC0-"L00000000001$pb"(%ebx), %eax
movl %eax, (%esp)
call L_puts$stub
.stabd 68,0,5
movl $0, %eax
.stabd 68,0,6
addl $20, %esp
popl %ebx
popl %ebp
ret
.stabs "main:F(0,2)",36,0,3,_main
.stabs "argc:p(0,2)",160,0,3,8
.stabs "argv:p(0,3)",160,0,3,12
.stabs "int:t(0,2)=r(0,2);-2147483648;2147483647;",128,0,0,0
.stabs ":t(0,3)=*(0,4)",128,0,0,0
.stabs ":t(0,4)=*(0,5)",128,0,0,0
.stabs "char:t(0,5)=r(0,5);0;127;",128,0,0,0
Lscope0:
.stabs "",36,0,0,Lscope0-_main
.stabd 78,0,0
.stabs "",100,0,0,Letext0
Letext0:
.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5
L_puts$stub:
.indirect_symbol _puts
hlt ; hlt ; hlt ; hlt ; hlt
.subsections_via_symbols
.section __TEXT,__textcoal_nt,coalesced,pure_instructions
.weak_definition ___i686.get_pc_thunk.bx
.private_extern ___i686.get_pc_thunk.bx
___i686.get_pc_thunk.bx:
movl (%esp), %ebx
ret

Good luck, hope this was helpful.

-Lee

Amdahl
Mar 20, 2008, 10:47 AM
In the end however, assembly has really fallen out of favor so to speak, and outside of completely "stand-alone" code, or for optimizing specific sections of code that require absolute maximum speed (assuming you have the knowledge to even optimize it further then the compiler), it really doesn't provide much "benefit" persay.

True, but:

Since CPU speeds have hit the wall, cases of single-thread performance bottleneck are everywhere, and they are only going away if the programmer sits down and does it. Becoming expert at assembly and algorithm performance (both single and parallel algorithms) is the one way to maximize the single-thread speed. SSE or custom instructions/cores is another approach. And if you are lucky enough to be dealing with a parallelizable problem, threading is there.

No matter which way you go, software is being forced to take up the weight that rising CPU speeds can no longer pull.

Cromulent
Mar 20, 2008, 04:46 PM
Just out of curiosity (as someone that has used x86 assembly on/off for over a decade) what do you hope to accomplish with assembly on Mac OSX?

Because it is the best way to achieve my main interest in computing, which is operating systems, compilers and simulators. All three make use of assembly in one way or another. I'll have to learn it at some point, may as well start now.

As with the others here, if you are attempting to learn x86 assembly, you will certainly have a far easier time using the extremely mature (and far better documented) assemblers found more prevalently on the Microsoft platforms (MASM in particular, but FASM or NASM might be good alternatives), and the general wealth of knowledge/examples for writing usable code that is available. On the other hand, you need to ensure you maintain a clear understanding of what is/is not available depending on what platform you are currently using...

Yes, I was thinking that myself. The only problem is my iTunes library is stored on my OS X partition and I find it an essential aid while programming :).

I've decided to try using NASM and then reading the Intel developer manuals linked earlier in this thread. Hopefully it won't be that hard.

In the end however, assembly has really fallen out of favor so to speak, and outside of completely "stand-alone" code, or for optimizing specific sections of code that require absolute maximum speed (assuming you have the knowledge to even optimize it further then the compiler), it really doesn't provide much "benefit" persay.

Personally I think this is a real shame. Although compilers are very good at producing optimised code, knowledge of assembly seems to give a huge advantage even when just doing C coding as it gives you a greater understanding of what is going on behind the scenes. At least that is what I am lead to believe and it seems like it is true from the little that I have looked into the subject.

<snip>

Thank you. That was some useful information.

True, but:

Since CPU speeds have hit the wall, cases of single-thread performance bottleneck are everywhere, and they are only going away if the programmer sits down and does it. Becoming expert at assembly and algorithm performance (both single and parallel algorithms) is the one way to maximize the single-thread speed. SSE or custom instructions/cores is another approach. And if you are lucky enough to be dealing with a parallelizable problem, threading is there.

No matter which way you go, software is being forced to take up the weight that rising CPU speeds can no longer pull.

This is one of the primary reasons I'm interested in low level programming. High level languages promote bloated programs that waste computer resources and I am still not convinced by the arguments that say computers are fast enough for it not to matter.

gnasher729
Mar 20, 2008, 06:23 PM
Here is the code that gcc produced for me (I removed some debug information, and I used the C++ compiler, that shouldn't make a difference):

size_t my_strlen (char *p) {
char* q = p;
while (*q) ++q;
return (size_t) (q - p);
}

__Z9my_strlenPc:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %edx
movl %edx, %eax
jmp L113

L114:
incl %eax
L113:
cmpb $0, (%eax)
jne L114
leave
subl %edx, %eax
ret


__Z9my_strlenPc:
mr r2,r3
b L122
L123:
addi r3,r3,1
L122:
lbz r0,0(r3)
cmpwi cr7,r0,0
bne cr7,L123
subf r3,r2,r3
blr

Flynnstone
Mar 20, 2008, 06:24 PM
I agree with Domain.

Very little of an OS is written in assembler.
Don't do assembly unless you have to.
Programmers are notoriously wrong at optimizing code.

You need to profile the code to find out where the "hotspots are".
Once you know where the bottle neck code is, you work on the algorithm.
Then you get it down to a small chunk of code that needs to be optimized, you then look to see if assembler will be any help.

Assembler is very processor specific. Obviously assembler for x86 is not going to work on a PowerPC. But since you're going for speed, you also need to know what processor (x86) you're running. A specific set of instructions for one x86 may not be optimized for another x86 (Pentium vs Core vs ...).
Optimized assembler is VERY CPU specific.
You generally need to be very good at assembler to beat the compiler.

Always profile before and after to see if you made an improvement.

Did I say "Don't do assembler unless you have to" ?

GCC isn't a great optimizing compiler. Its a great general compiler.
Optimizing for x86, its probably wise to get the Intel compiler. But you must profile to compare.

gnasher729
Mar 20, 2008, 06:37 PM
This is one of the primary reasons I'm interested in low level programming. High level languages promote bloated programs that waste computer resources and I am still not convinced by the arguments that say computers are fast enough for it not to matter.

I've done quite a bit of programming with code efficiency being the most important concern. Here is my experience:

1. In bigger projects, trying to write efficient code is not what gives you the big gains. Finding bits of code that are completely brain damaged insanely stupid and wasting time, and replacing them with something that is not completely stupid, that gives you big gains (sad but true).

2. Good C code is faster than bad assembler code. And there is some really bad assembler code around.

3. When you are developing algorithms that need to be fast, the important thing is to start with something that works, then study its behaviour, get a mental grasp of the problem, find out what makes the algorithm take time, get ideas to make it faster and implement them. It is not uncommon to get a factor 100 in speed from the first, not really inefficient approach to the final result, going through many rounds of iterative improvement. That approach doesn't work with assembler, you get too soon stuck in the tiny details and lose the bigger picture.

Muncher
Mar 20, 2008, 08:19 PM
I've decided to try using NASM and then reading the Intel developer manuals linked earlier in this thread. Hopefully it won't be that hard.

This is one of the primary reasons I'm interested in low level programming. High level languages promote bloated programs that waste computer resources and I am still not convinced by the arguments that say computers are fast enough for it not to matter.

NASM - good choice. I think you can integrate it with xcode, but I'm not entirely sure since Gas uses AT&T syntax.

I started out with Dark Basic about 5~6 years ago, making simple games and demos. I couldn't figure out why a program I made that struggled under Dark Basic would run 5x as fast when someone else made it. I then moved on to C, and found out why. Since then I've programmed for the PIC micro-controllers in ASM/C, and I really learned a lot from that. Maybe if you're interested in ASM, you should try micro-controllers. You can do a lot of cool things with them, and they may be slow, but the PIC instruction set is a whooping 35 instructions.

No matter how you cut it though, I personally would never to write an entire program in assembly for OS X. Maybe linux, but just looking at the Mach-o file format gives me a headache.

domain
Mar 20, 2008, 11:16 PM
Because it is the best way to achieve my main interest in computing, which is operating systems, compilers and simulators. All three make use of assembly in one way or another. I'll have to learn it at some point, may as well start now.

Yes, I was thinking that myself. The only problem is my iTunes library is stored on my OS X partition and I find it an essential aid while programming :).

I've decided to try using NASM and then reading the Intel developer manuals linked earlier in this thread. Hopefully it won't be that hard.

Personally I think this is a real shame. Although compilers are very good at producing optimised code, knowledge of assembly seems to give a huge advantage even when just doing C coding as it gives you a greater understanding of what is going on behind the scenes. At least that is what I am lead to believe and it seems like it is true from the little that I have looked into the subject.

Learning assembly from a standpoint of an interest in computing is certainly admirable... I have always believed that it should be on the first languages taught from a programming perspective, not because of it's practical application, but it gives you great insight into what is actually going on at the lowest levels, and at the same time trains to you think differently when it comes to writing code in higher level languages.

As for your iTunes dilemma, a very useful solution to said problem is to use a product like VMWare, which will let you work in a somewhat "clean" environment, while at the same time providing a safe place for a language that has the capabilities of doing actual destructive things (you'd be amazed how a simple typo in assembly can have some really *interesting* results :p)

So to learn for learning sake is a good thing (TM), on the other hand assembly's place in todays computing is very very limited. As per your Operating System example, very little assembly comes into play beyond the boot-loader stage (initial load, a20 initialization, protected mode, setting up IVT, etc.), unless you look at some very specific designs (there are more then a few all-assembly Operating Systems out there, Menuet comes to mind).

Also as some of the other posters have mentioned, the largest speed gains generally come from better algorithms, rather then hand optimized assembly. The general process is to find "problem areas", identify the algorithms involved, adjust/replace as necessary, and only then if it is still not fast enough move to assembly. That said (and I don't really care which you are using), compilers are very bad at optimizing... there are many many instances where the generated code has room for improvement, however if that segment of code isn't frequently called, then there is very little reason to do so.

At any rate, if you decide to use the Microsoft platforms as a learning base, I suggest you Google a few resources... Win32asm and Masm32 (as a baseline), The Art of Assembly (the assembly bible but use the old DOS edition!), and articles by Agner Fog (a number of great articles/papers that will show you how painful but powerful optimization can be). Thats all I can think of at the moment... just keep in mind this information was largely relevant for Intel x86 many years ago... the concepts for newer chips will remain the same, but the methods can be quite different (look up Itanium assembly sometime :p)

Cromulent
Mar 21, 2008, 10:28 AM
Considering this thread is now pretty high in Google page rank when searching for information about assembler for Mac OS X I thought I would link some useful information I have found.

1) To call the kernel in Mac OS X use the same code as for FreeBSD (0x80).

2) Mac OS X ABI Function Call Guide.

http://developer.apple.com/documentation/DeveloperTools/Conceptual/LowLevelABI/Introduction.html

3) http://www.x86-64.org/

All the information you need about 64bit programming.

4) Use the version of NASM that Apple ship with Xcode.

I'll update this post as I find more information.

MrStevieP
Mar 21, 2008, 11:38 AM
I have to disagree with those who have posted that asm has very limited use in the modern age. To give you some background, I am an embedded software engineer. My background ranges from set top boxes to raid controllers to traffic lights. In pretty much all the code I have seen, and at every office where I have worked, some proportion has been asm.

From an OS perspective, yes asm may have limited use. However, in the embedded world it is very much still used and will continue to be!! The only problem is that less and less people know it, so anyone going out of their way to learn asm in this day and age should be congratulated and stick it prominently on their CV. They will be snapped up at lightning speed!

Cromulent, I wish you well with your voyage of asm discovery!

Mr StevieP

Cromulent
Mar 21, 2008, 02:21 PM
Thank you all for the advice and encouragement. I've found it most useful.

Now for the stupid noob questions :).

SECTION .data
msg: db 'Hello World',10

len: equ $-msg ; get the length of the string

SECTION .text
global start

start:

mov edx, len ; length of the string
mov ecx, msg ; the string
mov ebx, 1 ; write()
mov eax, 4 ; stdout
int 0x80 ; kernel call

mov ebx, 0 ; start exit procedure
mov eax, 1
int 0x80

It assembles and links fine using the following commands:

nasm -f macho hello.s
ld -o hello hello.o

but does not work. Basically it runs but does not print anything at all. I'm fairly certain the code is correct as a number of tutorials use the same code for the Hello World program. Am I doing something completely stupid?

lee1210
Mar 21, 2008, 08:34 PM
Give this a try:
SECTION .data
msg db 'Hello World',0xa ;String to print
len: equ $-msg ; get the length of the string

SECTION .text
global _start


_start:
enter 0,0 ; Entry
pusha
push dword len ; Push length onto the stack
push dword msg ; Push address of msg onto the stack
push dword 0x1 ; We want to write to file 1, stdout
mov eax, 0x4 ; We want to call system function 4
push dword eax ; This is for stack alignment
int 0x80 ; Make the system call
add esp,16 ; Realign the stack
push dword 0; start exit procedure
mov eax, 0x1; Set system exit call
int 0x80 ; Make the system call


The code example you found is for a different call style. It will work on linux, or BSD if you do:
brandelf -f Linux <filename>

I tried it on OS X and it wasn't in my path, so I tried the "unix style" calling, using the stack for arguments based on a different example.

It took me a while to get it going, but this seems to be working for me.

-Lee

domain
Mar 21, 2008, 09:30 PM
As an addition to what lee posted (describes the difference between the code to some degree):

http://asm.sourceforge.net/intro/hello.html

Just remember OSX's BSDishness :p

Cromulent
Mar 22, 2008, 06:24 AM
<snip>

Thank you. Right now I know what the correct syntax is for Mac OS X assembly I can move forward. I've read so many tutorials and because I didn't know I didn't know if they were in the correct style or not.

That was incredibly useful.

Interestingly though the program you posted above only worked on my machine if I swapped the write() function and the file descriptor functions around. It said bad system call otherwise.

Also assembly does not seem to interpret '\n' as C does. I guess I'll need to use the raw code for a new line character and the append it on the end of every string?

Edit : It seems you don't need a newline character at all. Hmm that's odd, I would have thought you would have had to explicitly state that you wanted to have a newline?

lee1210
Mar 22, 2008, 08:33 AM
I'm not sure about the argument order. That was the order in the ex. I found. In the example I posted the newline is explicitly included. It is the 0xa after the string. That's the ASCII newline. Grab an ASCII chart, as the C escape sequences will not work. If you used C bindings then called libc's printf, you obviously could, but you'd need to take care in null terminating then.

-Lee

I apologize for typos in this. Posted from my phone.

Cromulent
Mar 22, 2008, 09:50 AM
I'm not sure about the argument order. That was the order in the ex. I found. In the example I posted the newline is explicitly included. It is the 0xa after the string. That's the ASCII newline. Grab an ASCII chart, as the C escape sequences will not work. If you used C bindings then called libc's printf, you obviously could, but you'd need to take care in null terminating then.

-Lee

I apologize for typos in this. Posted from my phone.

Ah, I see. It is all starting to make sense now :). Excellent, onwards and upwards as they say.

Cromulent
May 14, 2008, 03:42 PM
I know this is an old thread but I thought I would bump it as I found some interesting information. For those (like me) who are interested in ASM but feel a little lost at the start the High Level Assembly language seems like a great way to get into it. Think of it as mid way between ASM and C.

The book is available free here (http://webster.cs.ucr.edu/).

The Mac OS X version of the library / compiler is here (http://www.apple.com/downloads/macosx/development_tools/highlevelassemblerformacosx.html).

If anyone needs a hand getting it setup let me know, the instructions in the book are just for Linux / Windows but it is pretty straight forward on Mac OS X too.

Muncher
May 14, 2008, 07:11 PM
I know this is an old thread but I thought I would bump it as I found some interesting information. For those (like me) who are interested in ASM but feel a little lost at the start the High Level Assembly language seems like a great way to get into it. Think of it as mid way between ASM and C.

The book is available free here (http://webster.cs.ucr.edu/).

The Mac OS X version of the library / compiler is here (http://www.apple.com/downloads/macosx/development_tools/highlevelassemblerformacosx.html).

If anyone needs a hand getting it setup let me know, the instructions in the book are just for Linux / Windows but it is pretty straight forward on Mac OS X too.

Back from the dead! :p I've heard of that, but I didn't know it had an os x variant. Cool :D.

brian6504
May 14, 2008, 08:10 PM
I learned MIPS assembly, which is similar to PowerPC, but used the SPIM emulator to develop. I would recommend using some sort of emulation tool so you can see the registers and stack all the time and not have worry about working your way through a debugger.

After that it was pretty easy to pick up PowerPC and x86.