Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Cromulent

macrumors 604
Original poster
Oct 2, 2006
6,802
1,096
The Land of Hope and Glory
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.
 

Amdahl

macrumors 65816
Jul 28, 2004
1,438
1
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

macrumors 65816
Apr 19, 2007
1,465
0
California
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

Suspended
Nov 25, 2005
17,980
5,565
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

macrumors 6502
Jun 16, 2004
352
0
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:
Code:
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:
Code:
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:
Code:
mr r2, r3
b *+8
addi r2, r2, 1
lbz r0, 0(r2)
extsb. r0, r0
bne *-12
subf r3, r3, r2
blr
 

Cromulent

macrumors 604
Original poster
Oct 2, 2006
6,802
1,096
The Land of Hope and Glory
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:
Code:
    .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?
Code:
.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

macrumors 6502
Jun 16, 2004
352
0
You need the data section too (the part above the blob of code you gave that has .ascii "Hello, World!\0" in it)
 

Cromulent

macrumors 604
Original poster
Oct 2, 2006
6,802
1,096
The Land of Hope and Glory
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

macrumors 6502
Jun 16, 2004
352
0
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

macrumors 604
Original poster
Oct 2, 2006
6,802
1,096
The Land of Hope and Glory
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

macrumors member
Jan 25, 2007
35
0
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

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
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:
Code:
#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:
Code:
        .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:
Code:
        .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

macrumors 65816
Jul 28, 2004
1,438
1
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

macrumors 604
Original poster
Oct 2, 2006
6,802
1,096
The Land of Hope and Glory
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.


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

Suspended
Nov 25, 2005
17,980
5,565
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):

Code:
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

macrumors 65816
Feb 25, 2003
1,438
96
Cold beer land
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

Suspended
Nov 25, 2005
17,980
5,565
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

macrumors 65816
Apr 19, 2007
1,465
0
California
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

macrumors member
Jan 25, 2007
35
0
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

macrumors 604
Original poster
Oct 2, 2006
6,802
1,096
The Land of Hope and Glory
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

macrumors newbie
Feb 27, 2008
22
0
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

macrumors 604
Original poster
Oct 2, 2006
6,802
1,096
The Land of Hope and Glory
Thank you all for the advice and encouragement. I've found it most useful.

Now for the stupid noob questions :).

Code:
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

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
Give this a try:
Code:
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
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.