Porting to Intel IV – W00t!

I got a major part of my application working on the Intel Mac.

Here are a few macros I came up with to handle the byte ordering issues when reading & writing binary data from a file:

#define W(w) ((unsigned short)w)
#define WSWAP(w) (W((W(w) << 8 ) | (W(w) >> 8 )))
#define DW(d) ((unsigned long)d)
#define DWSWAP(d) ((DW(d) >> 24) | ((DW(d) >> 8 ) & 0xff00) | ((DW(d) & 0xff00) << 8 ) | (DW(d) << 24))

#if defined(__LITTLE_ENDIAN__)
#define LITTLE_ENDIAN_WORD(w) W(w)
#define LITTLE_ENDIAN_DWORD(d) DW(d)
#define BIG_ENDIAN_WORD(w) WSWAP(w)
#define BIG_ENDIAN_DWORD(d) DWSWAP(d)
#else
#define LITTLE_ENDIAN_WORD(w) WSWAP(w)
#define LITTLE_ENDIAN_DWORD(d) DWSWAP(d)
#define BIG_ENDIAN_WORD(w) W(w)
#define BIG_ENDIAN_DWORD(d) DW(d)
#endif

Porting to Intel III

The XCode debugger (and gdb) will confuse you with word & long values. For example, I have an IP address & port stored as the bytes 00 50 c0 a8 0 64 (that’s 192.168.0.100:80). Displaying memory in the debugger will show it as a8c05000 00006400 if you use the default word size of 4. Setting the word size to 1 will show the proper values.

Porting to Intel II

Never assume Macs are big-endian. I found code which uses #ifdef __MAC__ to decide whether byte order swapping is required – that’s just plain wrong.

Porting to Intel

An IP address is not a long int – it’s 4 bytes. Doing something like this is bad:

sprintf(buf,”%ld.%ld.%ld.%ld”, (ip>>24) & 255, (ip>>16) & 255, (ip>> 8 ) & 255, ip & 255);

What I learned

I’ve been on a coding streak for the last day, which is why I haven’t written anything here. I discovered a few interesting things.

  1. The easiest way to open the default browser and go to a URL is with /usr/bin/open. Rather than using the Launch Services API or InternetConfig, simply do system("/usr/bin/open some_url"). It will do the right thing.
  2. Safari is a huge pain. I was able to get something working in every browser EXCEPT Safari. Safari’s very aggressive caching causes the wrong page to display, even when I add cache control headers. Safari also insists on sending POST requests for some javascript navigation buttons rather than GET requests which every other browser sends.
  3. MFC is ugly (I already knew this). Porting MFC code to the Mac is even uglier.

Cartooner 1.0

I’ve released an enhanced version of my ADHOC 2005 showcase hack as Cartooner 1.0. It can be downloaded here, including full source code. Cartooner is free & open source. It requires an iSight and runs in Tiger.

Gateway Enhances Notebook Security With Absolute Software's Computrace

Gateway, continuing its commitment to provide its education, government and professional customers with enterprise-grade solutions, will start integrating two leading security technologies into its professional notebook and desktop product line up.

Gateway’s new Mobile Theft Protection Solution minimizes the incalculable costs associated with stolen notebook PCs by adding Absolute(R) Software’s Computrace technology into the firmware, bringing data security to the core of the system that cannot be removed or altered. The systems will also integrate
the industry’s latest hardware security standard — Trusted Platform Module (TPM) 1.2.

(via PRNewsWire)

My hack

My showcase hack from ADHOC used a Quartz composition to add comic effects to live video from an iSight. I used some Apple sample code involving Quartz compositions which also had a lot of extra stuff I didn’t need. I left in all of the crud for my demo, but I’m now completely rewriting it from scratch and enhancing it. This will be my first non-trivial Cocoa application.

Attack of the zombie processes

I have an application that consists of a background process which launches another tool at certain times to do some work. I was doing this the standard Unix way:

if ((pid = fork()) == 0) {
    exec("/some/application");
} else {
    wait(&status);
}

I’ve been attempting to convert it to a single binary rather than two separate files. I figured I could simply have it run the code to do the timed task inline after I fork() instead of launching a separate binary.

I found that the forked process was crashing immediately when it attempted to use a CFRunLoop function. Even more annoying, the child process can’t be debugged in gdb as far as I can tell. It ended up crashing, and getting respawned so quickly it filled up the process table with zombie processes so I could no longer run anything else.

$ ps ax
-bash: fork: Resource temporarily unavailable

It turns out you can’t continue after a fork() without execing.

The problem is that fork() does not actually replicate all kernel resources (and perhaps other bits I don’t know about) from the parent process into the child, but it does replicate memory. Thus there can be code which thinks everything is happy because the memory holding handles to kernel esources looks like it is initialized and whatnot, but the kernel resources are missing underneath.

Basically, after fork() you need to execve() (or other exec variant), so that library initializers and whatnot are executed in the context of the child to do any 1-time set-up or whatever else the libraries normally do when an app is launched.

Thanks to Chris Hanson for pointing this out.

Mac x86 porting

Although I don’t have the x86 development system, I’ve been using XCode 2.1. For one of my projects, I was able to convert to x86 in less than 15 minutes. I simply opened the project in XCode 2.1, selected the 10.4 universal SDK, chose intel & ppc architectures, and made sure it was using GCC 4.0. I got lots of errors because GCC 4.0 is a lot more fussy about pointer conversions, so I temporarily eliminated them with the option “Treat nonconformant code errors as warnings”.

It compiled and when I examine the binary, it’s identified as ‘Mach-O fat file with 2 architectures’. Of course I can’t actually test it on an x86 machine. I also haven’t attempted to deal with any endian issues, since the application deals with binary data.

This is a pretty good indication that developing for the Intel macs will be painless.