From a quick skim of the two sources, the difference in sizes can be attributed to:
1) The GNU version has MUCH more verbose commenting
2) The GNU version reads input in blocks in cooked mode, rather than a character at a time as the BSD cat does. This is MUCH faster, but it leads to a lot more complexity, and thus more code. It also carefully calculates the optimal block size to use for this; this is also quite complex and carefully commented (see, eg, the 20 line comment at line 736).
3) The GNU version has to be portable to multiple unixes, and thus has a number of places where it has to test for multiple error codes, and/or missing features
4) The GNU version has a very verbose --help output, which consumes a good page or so of code by itself.
I don't really see any 'bloat' there. Sure, it's okay to have a simple cat, but it's not a bad idea to optimize a tool that's used so frequently. And the verbose --help output, verbose commenting, and portability are all part of the GNU coding standards. You can argue about whether you want to spend all that effort on it, but I don't think the sheer volume of code is a good measure for whether the code is good or not.